给出2个数列,{ai},{bi}.要求支持以下操作
- 修改数列a的第i个为x
- 修改数列b的第i个为x
- 给出k,求最小的t,满足∑⌊ait−bi⌋≥k
操作数不多于100000,操作3不多于1000;数列长度不多于10000,a的值域不大于1000。
分析
将⌊ait−bi⌋拆开,观察前后可能出现的差。
⌊ait⌋−⌊aibi⌋
设t=k1ai+c1,bi=k2ai+c2,代入观察。
⌊ait−bi⌋=⌊ai(k1−k2)ai+c1−c2⌋
可以发现,当把式子拆开时,有2种情况。
- c1>c2,啥事没有。
- c1<c2,拆开后会多统计一个1。
事先统计{bi}模a的余数,那么有t后就能快速数出第2种情况的数量。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #include <iostream> #include <algorithm> #include <cstring> using namespace std; using ll=long long; const int MAXA=1010,MAXB=100010;
int nlen,mlen; int a[MAXB],acnt[MAXA]; int b[MAXB];
int fts[MAXA][MAXA]; int pre[MAXA][MAXA];
void force(int i){ pre[i][0]=fts[i][0]; for(int j=1;j<MAXA;j++){ pre[i][j]=pre[i][j-1]+fts[i][j]; } }
ll base=0;
bool check(ll k,ll t){ ll res=-base; for(int i=1;i<=1000;i++){ res+=(t/i)*acnt[i]; int c=t%i; ll offset=pre[i][1000]-pre[i][c]; res-=offset; } return res>=k; }
int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int kase;cin>>kase; while(kase--){ memset(acnt,0,sizeof(acnt)); memset(a,0,sizeof(a)); base=0; memset(fts,0,sizeof(fts)); cin>>nlen>>mlen; for(int i=1;i<=nlen;i++){ cin>>a[i]; acnt[a[i]]+=1; } for(int i=1;i<=nlen;i++){ cin>>b[i]; fts[a[i]][b[i]%a[i]]++; base+=b[i]/a[i]; } for(int i=1;i<=1000;i++){ force(i); }
for(int i=1;i<=mlen;i++){ int opt; cin>>opt; if(opt==1){ int x,y; cin>>x>>y;
acnt[a[x]]--; fts[a[x]][b[x]%a[x]]--; base-=b[x]/a[x]; force(a[x]);
a[x]=y; fts[a[x]][b[x]%a[x]]++; acnt[a[x]]++; base+=b[x]/a[x]; force(a[x]);
}else if(opt==2){ int x,y; cin>>x>>y;
fts[a[x]][b[x]%a[x]]--; base-=b[x]/a[x]; force(a[x]);
b[x]=y;
fts[a[x]][b[x]%a[x]]++; force(a[x]); base+=b[x]/a[x]; }else if(opt==3){ int qk;cin>>qk; ll l=0,r=1e13; while(l+1<r){ ll mid=(l+r)/2; if(check(qk,mid)){ r=mid; }else l=mid+1; } for(ll i=l;i<=r;i++){ if(check(qk,i)){ cout<<i<<"\n"; break; } } } } } return 0; }
|