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