ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF-edu131-div2

2022-07-10 16:35:15  阅读:160  来源: 互联网

标签:int ll edu131 cin CF 任务 端点 ask div2


C.Schedule Management(二分)

Problem

现在有\(m\)个任务和\(n\)个工人,擅长第\(i\)个任务的人是\(a_i\)。存在擅长该任务的人做该任务花费时间为\(1\)小时,不擅长该任务的人做该任务需要花费\(2\)个小时,每个时刻一个人只能做一个任务,工人可以并行工作,问最少花费多少时间可以把任务做完

Solve

二分,每次二分一个完成时间,计算小于这个时间的工人可以额外多完成多少件任务\(extr\),大于这个时间的工人需要多少个人来帮他完成多出的任务\(need\),如果\(extr>=need\),说明时间又太多有剩余,把范围缩小

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int T;
  cin>>T;
  while(T--){
    int n,m;
    cin>>n>>m;
    vector<int>cnt(n+1);
    for(int i=1;i<=m;i++){
      int x;
      cin>>x;
      cnt[x]++;
    }
    int l=0,r=m;
    while(l<r){
      ll extr=0,need=0;
      int mid=l+r>>1;
      for(int i=1;i<=n;i++){
        if(cnt[i]<=mid) extr+=(mid-cnt[i])/2;
        else need+=cnt[i]-mid;
      }
      if(extr>=need) r=mid;
      else l=mid+1;
    }
    cout<<l<<'\n';
  }
}

D.Permutation Restoration

Problem

有个长度为\(n\)的排列\(p\),但现在不知道\(p\),知道长度为\(n\)的序列\(b\),满足\(b_i=\lfloor \frac{i}{p_i}\rfloor\),要你求出原来的排列\(p\)。

Solve

对于每个\(p_i\),都可以求出一个取值范围\([l_i,r_i]\)。考虑吧所有的区间按照左端点从小到大排序,线性扫一遍的得出。
image

按照左端点从小到大排序,对于左端点相同,右端点越小一定越先选择,右端点越大,可选择的机会越多,而越往后扫,由于左端点递增,如果右端点不是不是很大的话,后加的反而选择会少,反而要先选,所以用一个优先队列维护右端点,每次选择右端点最小的赋值。扫的话\(i\)从\(1\)开始,考虑把\(i\)给原序列的第几个数。比较经典的问题

Code

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
array<int,3>seg[N];
int main()
{
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int T;
  cin>>T;
  while(T--)
  {
     int n;
     cin>>n;
     vector<int>b(n+1),p(n+1);
     for(int i=1;i<=n;i++) cin>>b[i];
     for(int i=1;i<=n;i++){
        if(b[i]==0) seg[i][0]=i+1,seg[i][1]=n;
        else{
          seg[i][1]=i/b[i];
          seg[i][0]=i/(b[i]+1)+1;
        
        }
        seg[i][2]=i;
     }
     sort(seg+1,seg+1+n);
     priority_queue<pair<int,int>>q;
     int j=1;
     for(int i=1;i<=n;i++){
       while(j<=n&&seg[j][0]==i){
         q.push({-seg[j][1],seg[j][2]});
         ++j;
       }
       p[q.top().second]=i;
       q.pop();
     }
     for(int i=1;i<=n;i++) cout<<p[i]<<" \n"[i==n];
  }
}

F.Points(线段树、树状数组)

Problem

一个水平坐标轴上,三个点\(i\lt k \lt j\)称为漂亮点对满足\(j-i\le d\)。一开始坐标轴上没有点,现在有\(q\)次询问,每次给出一个点的坐标\(x\gt 0\),如果这个点不存在,就加上这个点,并计算现在有多少漂亮点对;若果这个点不存在,就把这个点删去,并计算现在有多少个漂亮点对

Solve

image

Code

#include <bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
#define ll long long
using namespace std;
const int N=2e5,NN=2e5;
int a[NN],vis[NN];
int q,d;
int cnt[NN*4],tag[NN*4];
ll sum[NN*4];
void add(int p,int x){
    for(;p<=N;p+=p&-p) a[p]+=x;
}
int ask(int p){
    int res=0;
    for(;p;p-=p&-p) res+=a[p];
        return res;
}

void pushup(int rt){
   cnt[rt]=cnt[ls]+cnt[rs],sum[rt]=sum[ls]+sum[rs];
}
void pushdown(int rt){
    if(tag[rt]){
        sum[ls]+=1LL*tag[rt]*cnt[ls];
        sum[rs]+=1LL*tag[rt]*cnt[rs];
        tag[ls]+=tag[rt];
        tag[rs]+=tag[rt];
        tag[rt]=0;
    }
}
void update1(int rt,int L,int R,int p,int x){ //单点修改
    if(L==R){
        if(cnt[rt]) cnt[rt]=0,sum[rt]=0;
        else cnt[rt]=1,sum[rt]=x;
        return;
    }
    pushdown(rt);
    int mid=L+R>>1;
    if(p<=mid) update1(ls,L,mid,p,x);
    else update1(rs,mid+1,R,p,x);
    pushup(rt);
}
void update2(int rt,int L,int R,int l,int r,int x){ //区间修改 
    if(R<l||L>r) return ;
    if(l<=L&&R<=r){
        sum[rt]+=1LL*x*cnt[rt];
        tag[rt]+=x;
        return;
    }
    pushdown(rt);
    int mid=L+R>>1;
    if(l<=mid) update2(ls,L,mid,l,r,x);
    if(r>mid) update2(rs,mid+1,R,l,r,x);
    pushup(rt);
}
ll query(int rt,int L,int R,int l,int r){
    if(R<l||L>r) return 0;
    if(l<=L&&R<=r){
        return sum[rt];
    }
    pushdown(rt);
    ll res=0;
    int mid=L+R>>1;
    if(l<=mid) res+=query(ls,L,mid,l,r);
    if(r>mid) res+=query(rs,mid+1,R,l,r);
    return res;
}
ll cal(int x){
    int cntl=ask(x-1)-ask(max(x-d-1,0));
    int cntr=ask(min(x+d,N))-ask(x);
    ll res=query(1,1,N,x-d,x-1)+1LL*cntr*(cntr-1)/2;
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>q>>d;
    ll ans=0;
    while(q--){
        int x;
        cin>>x;
        if(!vis[x]){
            vis[x]=1;
            ans+=cal(x);
            add(x,1);              
            update2(1,1,N,x-d,x-1,1);   
            update1(1,1,N,x,ask(min(x+d,N))-ask(x));
        }else{
            vis[x]=0;
            update1(1,1,N,x,0);
            update2(1,1,N,x-d,x-1,-1);
            add(x,-1);
            ans-=cal(x);
        }
        cout<<ans<<'\n';
    }
}

标签:int,ll,edu131,cin,CF,任务,端点,ask,div2
来源: https://www.cnblogs.com/Arashimu0x7f/p/16463375.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有