HDU-6274 Master of Sequence
题意
给出两个长度为(n)的数组(a)和(b),设(S(t)=sum_{i=1}^{n} lfloor frac{t-b_i}{a_i} floor),(m)组操作:
- (1~x~y),将(a[x])改为(y)。
- (2~x~y),将(b[x])改为(y)。
- (3~k),询问 ( ext{min} {t|kle S(t) })。
(nle 10^5,mle 10^4,a_i le 1000,b_i,kle 10^9),第三种操作个数不超过(1000)。
分析
先把公式拆分一下。
[S(t)=sum_{i=1}^{n} lfloor frac{t-b_i}{a_i}
floor \
=sum_{i=1}^{n} lfloor frac{k1cdot a_i+t\%a_i-k2cdot a_i-b_i\%a_i}{a_i}
floor \
=sum_{i=1}^{n} k1-k2-[t\%a_i-b_i\%a_i<0]
]
由于(a_ile 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
",l);
}
}
}
return 0;
}