HDU-6274 Master of Sequence 数学+二分
HDU-6274 Master of Sequence
题意
给出两个长度为\(n\)的数组\(a\)和\(b\),设\(S(t)=\sum_{i=1}^{n} \lfloor \frac{t-b_i}{a_i} \rfloor\),\(m\)组操作:
- \(1~x~y\),将\(a[x]\)改为\(y\)。
- \(2~x~y\),将\(b[x]\)改为\(y\)。
- \(3~k\),询问 \(\text{min} \{t|k\le S(t) \}\)。
\(n\le 10^5,m\le 10^4,a_i \le 1000,b_i,k\le 10^9\),第三种操作个数不超过\(1000\)。
分析
先把公式拆分一下。
\[S(t)=\sum_{i=1}^{n} \lfloor \frac{t-b_i}{a_i} \rfloor \\
=\sum_{i=1}^{n} \lfloor \frac{k1\cdot a_i+t\%a_i-k2\cdot a_i-b_i\%a_i}{a_i} \rfloor \\
=\sum_{i=1}^{n} k1-k2-[t\%a_i-b_i\%a_i<0]
\]
由于\(a_i\le 1000\),我们二分\(t\)的大小,对每种\(a_i\)用桶分别计算\((t\%a_i-b_i\%a_i<0)\)的个数。
Code
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int T,n,m;
int a[N],b[N];
int sz[1010];
int sum[1010][1010];
inline bool ck(ll x,ll k){
ll ret=0;
for(int i=1;i<=1000;++i){
ret+=x/i*sz[i]-sum[i][x%i+1];
}
return ret>=k;
}
int main()
{
scanf("%d",&T);
while(T--){
ll res=0;
scanf("%d%d",&n,&m);
memset(sz,0,sizeof sz);
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
res+=b[i]/a[i];
sum[a[i]][b[i]%a[i]]++;
sz[a[i]]++;
}
for(int i=1;i<=1000;i++){
for(int j=1000;j>=0;j--) sum[i][j]+=sum[i][j+1];
}
for(int i=1,op,x,y;i<=m;i++){
scanf("%d%d",&op,&x);
if(op==1){
scanf("%d",&y);
res-=b[x]/a[x];
for(int j=0;j<=b[x]%a[x];j++) sum[a[x]][j]--;
sz[a[x]]--;
a[x]=y;
res+=b[x]/a[x];
for(int j=0;j<=b[x]%a[x];j++) sum[a[x]][j]++;
sz[a[x]]++;
}else if(op==2){
scanf("%d",&y);
res-=b[x]/a[x];
for(int j=0;j<=b[x]%a[x];j++) sum[a[x]][j]--;
sz[a[x]]--;
b[x]=y;
res+=b[x]/a[x];
for(int j=0;j<=b[x]%a[x];j++) sum[a[x]][j]++;
sz[a[x]]++;
}else{
ll l=0,r=1e13;
while(l<=r){
ll mid=l+r>>1;
if(ck(mid,x+res)) r=mid-1;
else l=mid+1;
}
printf("%lld\n",l);
}
}
}
return 0;
}