HDU - 6274 Master of Sequence (二分搜索+预处理)(2017CCPC杭州站K题)

题目链接:http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf


解题思路:对于操作三考虑二分+暴力,复杂度为 O(1000*N*log(T)),会超时。问题在于,我们对每一个T都重新遍历整个数组,计算最后的S(T),这里为O(N)复杂度,明显不行,考虑优化。观察数据得a只有1000,所以我们可以预处理所有的a,用sum[i],记录i为a中某个数时,分子和是多少,和cnt[i]记录a[i]出现过多少次,这样计算的公式为

        ll ans=0;
	for (int i=1; i<=1000; i++){
		ans+=floor( (cnt[i]*m-sum[i])/i );	
	}
	if (ans>=k) return true;
	return false;

感觉复杂度降到了1000,但是有个问题,题目要求是向下取整,所以不行,这样做可能会算多了一点。所以再考虑余数多出来的情况。

对于 (t-bi)/ai,我们可以化简成余数相加的形式,即 [ k1*ai+c1-(k2*ai+c2)] /ai ,对于k2的和,我们可以提前预处理出来然后移项,整个不等式变为  k+sum(k2)《=  西格玛 [(k1*ai+c1-c2 )/ai]

这样子我们只需要判断c1和c2 的值了。如果c1>=c2,那么对答案无影响。如果c2>c1,那么明显,向下取整会导致多算了1,所以我们就统计下有多少个这种情况就好了,这里可以用树状数组去做,但是好像优化不了,因为会有很多次访问。


#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;

inline void scan_d(int &ret)
{
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9');
    while (c >= '0' && c <= '9')
    {
        ret = ret * 10 + (c - '0'), c = getchar();
    }
}

void Out(ll a)
{   //  输出外挂
    if (a < 0)
    {
        putchar('-');
        a = -a;
    }
    if (a >= 10)
    {
        Out(a / 10);
    }
    putchar(a % 10 + '0');
}

int num[1005][1005];//num[x][y]表示对于所有a[i]==x时的b[i]%a[i]余数大于等于y的数目
int a[100005];
int b[100005];
int x,y,k;
int N,M;

bool judge(ll res,ll m){
    ll ans=0;
    for (int i=1;i<=1000;i++){
        ans+=m/i*num[i][0];
        ans-=num[i][m%i+1];
    }
    if (ans>=k+res) return true;
    return false;
}


int main(){
    
    int t;
    scan_d(t);
    int op;
    ll m;
    while(t--){
        memset(num,0,sizeof(num));
        ll res=0;
        scan_d(N);
        scan_d(M);
        for(int i=1;i<=N;i++){
            scan_d(a[i]);
        }
        for(int i=1;i<=N;i++){
            scan_d(b[i]);
            num[a[i]][b[i]%a[i]]++;
            
            res+=(b[i]/a[i]);
        }
        for(int i=1; i<=1000;i++)
            for(int j=i-1;j>=0;j--)
                num[i][j]+=num[i][j+1];
        
        while(M--){
            scan_d(op);
            if(op==1){
                scan_d(x);
                scan_d(y);
                for(int i=b[x]%a[x];i>=0;i--)
                    num[a[x]][i]--;
                for(int i=b[x]%y; i>=0; i--)
                    num[y][i]++;
                res-=b[x]/a[x];
                res+=b[x]/y;
                a[x]=y;
            }
            else if(op==2){
                scan_d(x);
                scan_d(y);
                for(int i=b[x]%a[x];i>=0;i--)
                    num[a[x]][i]--;
                for(int i=y%a[x];i>=0;i--)
                    num[a[x]][i]++;
                res-=b[x]/a[x];
                res+=y/a[x];
                b[x]=y;
            }
            else{
                scan_d(k);
                ll l=1,r=10000000000000LL;
                while(l<r){
                    m=(l+r)>>1;
                    if(judge(res,m))
                        r=m;
                    else
                        l=m+1;
                }
                Out(l);
                puts("");
            }
        }
        
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/80193588
今日推荐