K. Master of Sequence (转化&二分)
对于操作3:
肯定要考虑将除法转化为求和才能方便计算。
令
t
=
a
i
×
k
1
+
c
1
,
b
i
=
a
i
×
k
2
+
c
2
t=a_i\times k_1+c_1,b_i=a_i\times k_2+c_2
t=ai×k1+c1,bi=ai×k2+c2
⌊
t
−
b
i
a
i
⌋
=
k
1
−
k
2
+
[
c
1
−
c
2
]
\lfloor\dfrac{t-b_i}{a_i}\rfloor\\=k_1-k_2+[c_1-c_2]
⌊ait−bi⌋=k1−k2+[c1−c2]
当
c
1
≥
c
2
,
[
c
1
−
c
2
]
=
0
c_1\geq c_2 ,[c_1-c_2]=0
c1≥c2,[c1−c2]=0
否则
[
c
1
−
c
2
]
=
−
1
[c_1-c_2]=-1
[c1−c2]=−1
因为
a
i
,
b
i
a_i,b_i
ai,bi已知,所以预处理出
k
2
k_2
k2的和。
式子可以转化为:
S
(
t
)
≥
k
→
∑
(
k
1
−
[
c
1
−
c
2
]
)
≥
∑
k
2
+
k
S(t)\geq k\rightarrow \sum (k_1-[c_1-c_2])\ge \sum k2+k
S(t)≥k→∑(k1−[c1−c2])≥∑k2+k
对于判断所有
[
c
1
−
c
2
]
=
−
1
[c_1-c_2]=-1
[c1−c2]=−1,我们可以用一个二维数组
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示数组
a
a
a中等于
i
i
i且
b
[
x
]
%
a
[
x
]
≥
j
b[x]\%a[x]\ge j
b[x]%a[x]≥j的个数。
这样对于当前
t
,
i
t,i
t,i,
c
n
t
=
d
p
[
i
]
[
t
%
i
+
1
]
cnt=dp[i][t\%i+1]
cnt=dp[i][t%i+1].
∑ ( k 1 − [ c 1 − c 2 ] ) = ∑ i = 1 1000 ( d p [ i ] [ 0 ] − d p [ i ] [ t % i + 1 ] ) \sum (k_1-[c_1-c_2])=\sum\limits_{i=1}^{1000} (dp[i][0]-dp[i][t\%i+1]) ∑(k1−[c1−c2])=i=1∑1000(dp[i][0]−dp[i][t%i+1])
然后二分找到 t t t即可。
时间复杂度: O ( 1 0 6 × l o g n + m ) O(10^6\times logn+m) O(106×logn+m)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define lx x<<1
#define rx x<<1|1
int t,n,m;
int a[N],b[N];
int dp[1005][1005];//dp[i][j] a[i] 的b[i]/a[i]>=j的个数
bool check(ll t,ll k){
ll ans=0;
for(int i=1;i<=1000;i++){
ans+=t/i*dp[i][0];
ans-=dp[i][t%i+1];
}
return ans>=k;
}
ll fun(ll x){
ll l=1,r=1e10;
ll ans=0;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid,x)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
ll s2=0;//sum (b[i]/a[i])
mst(dp,0);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]),s2+=b[i]/a[i],dp[a[i]][b[i]%a[i]]++;
for(int i=1;i<=1000;i++)
for(int j=i;j;j--) dp[i][j-1]+=dp[i][j];
while(m--){
int op,x,y,k;
scanf("%d",&op);
if(op==1){
scanf("%d%d",&x,&y);
s2-=b[x]/a[x];
s2+=b[x]/y;
for(int i=b[x]%a[x];~i;i--) dp[a[x]][i]--;
for(int i=b[x]%y;~i;i--) dp[y][i]++;
a[x]=y;
}
else if(op==2){
scanf("%d%d",&x,&y);
s2-=b[x]/a[x];
s2+=y/a[x];
for(int i=b[x]%a[x];~i;i--) dp[a[x]][i]--;
for(int i=y%a[x];~i;i--) dp[a[x]][i]++;
b[x]=y;
}
else {
scanf("%d",&k);
printf("%lld\n",fun(k+s2));
}
}
}
return 0;
}