题目链接: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; }