hdu6274(向下取整式子分解,二分判断)

题:http://acm.hdu.edu.cn/showproblem.php?pid=6274

题意:给定n(n<=1e5)的a[i]和b[i](a[i]<=1e3,b[i]<=1e9) 有m个操作操作一[x,y]:a[x]=y; 操作二[x,y]:b[x]=y;操作三[k]:输出最小的 x 使得S(x)>=k( S(x) =Σ(x-b[i])/a[i] )

分析:要求最小的,我们考虑对每个询问二分,因为题目保证操作三不会超过1e3次且x越大S(x)越能满足,满足单调性;

   关键在于S(x)的拆分,如果x,b[i]都整除a[i]的话,我们就可以拆分成x/a[i] 和b[i]/a[i] ,但是结果肯定不可能都是这样的;

   那么我们就先把这部分答案存进来,再来考虑不整除的情况,那就考虑取模x%a[i]和b[i]%a[i];

   这里假设x>b[i],若前者小于后者则相当于(x-b[i])/a[i]在直接算(x/a[i]-b[i]/a[i])少了1的贡献的(可以理解为在moda[i]意义下,他们之间间隔没有一个a[i]的长度)

   所以我们直接算sum(b[i]/a[i]),在二分x去算(x/a[i])和可能少了1的部分贡献(用树状数组去维护有多少个是大于(x%a[i])的);

   这里check里面,我们只要枚举余数即可,也就是说1e3次询问三复杂度为1e3*1e3*log1e9  ,10s时限没问题

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e5+5;
const int N=1e3+3;
int a[M],b[M],num[M];
int n,m;
struct BIT{
    int tr[N+3];
    void add(int i,int v){
        i++;
        for(;i<N;i+=i&-i) tr[i]+=v;
    }
    int sum(int x){
        int res=0;
        x++;
        for(int i=x;i;i-=i&-i) res+=tr[i];
        return res;
    }
}bit[N];

bool check(ll x,ll limit){
    ll res=0;
    ///枚举余数
    for(int i=1;i<=1000;i++){
        res+=(x/i)*num[i]-(num[i]-bit[i].sum(x%i));
        if (res>=limit) return 1;
    }
    return res>=limit;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        ll sum=0;
        memset(num,0,sizeof(num));
        memset(bit,0,sizeof(bit));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            scanf("%d",&b[i]);
            sum+=b[i]/a[i];
            bit[a[i]].add(b[i]%a[i],1);
            num[a[i]]++;
        }

        while(m--){
            int op,x,y;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&x,&y);
                sum+=b[x]/y-b[x]/a[x];
                bit[a[x]].add(b[x]%a[x],-1);
                bit[y].add(b[x]%y,1);
                num[a[x]]--,num[y]++;
                a[x]=y;
            }
            else if(op==2){
                scanf("%d%d",&x,&y);
                sum+=y/a[x]-b[x]/a[x];
                bit[a[x]].add(b[x]%a[x],-1);
                bit[a[x]].add(y%a[x],1);
                b[x]=y;
            }
            else{
                ll k;
                scanf("%lld",&k);
                ll l=0,r=2e12,ans;
                ll limit=k+sum;
                while(l<=r){
                    ll midd=(l+r)>>1;
                    if(check(midd,limit)){
                        ans=midd;
                        r=midd-1;
                    }
                    else l=midd+1;
                }
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2020-10-19 23:53  starve_to_death  阅读(142)  评论(0编辑  收藏  举报