【做题记录】2025刷题计划--根号算法

A. Tree Master

考虑根号分治,暴力处理。对于一层,设点数为 \(cnt\)

  • \(cnt>\sqrt{n}\),这样的层最多有 \(\sqrt{n}\) 层,每一层最多计算 \(q\) 次,时间复杂度为 \(O(q\sqrt{n})\)
  • 否则 \(cnt\le\sqrt{n}\),进行记忆化,每一层最多计算 \(cnt\choose 2\) 次,最多有 \(\frac{n}{cnt}\) 层,时间复杂度就是 \(O(n\sqrt{n})\) 的。

于是可以通过。空间复杂度 \(O(n\sqrt{n})\)

Code
复制代码
  • 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
#include<bits/stdc++.h> #define ll long long #define il inline #define pb push_back using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=1e5+5; int n,m,fa[maxn],cnt[maxn]; int dep[maxn],bfn[maxn],blen; ll a[maxn],**mem[maxn]; vector<int> e[maxn],cun[maxn]; queue<int> q; il ll dfs(int u,int v){ if(!u&&!v){ return 0; } if(cnt[dep[u]]<=blen&&~mem[dep[u]][bfn[u]][bfn[v]]){ return mem[dep[u]][bfn[u]][bfn[v]]; } ll res=a[u]*a[v]+dfs(fa[u],fa[v]); if(cnt[dep[u]]<=blen){ mem[dep[u]][bfn[u]][bfn[v]]=mem[dep[u]][bfn[v]][bfn[u]]=res; } return res; } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } int main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=2;i<=n;i++){ cin>>fa[i]; e[fa[i]].pb(i); } blen=sqrt(n); q.push(1); while(q.size()){ int u=q.front(); q.pop(); dep[u]=dep[fa[u]]+1; bfn[u]=cnt[dep[u]]; cun[dep[u]].pb(u); cnt[dep[u]]++; for(int v:e[u]){ q.push(v); } } for(int i=1;i<=n;i++){ if(cnt[i]<=blen){ mem[i]=new ll*[cnt[i]](); for(int j=0;j<cnt[i];j++){ mem[i][j]=new ll[cnt[i]](); for(int k=0;k<cnt[i];k++){ mem[i][j][k]=-1; } } } } while(m--){ int u,v; cin>>u>>v; cout<<dfs(u,v)<<"\n"; } for(int i=1;i<=n;i++){ if(cnt[i]<=blen){ for(int j=0;j<cnt[i];j++){ delete[] mem[i][j]; } delete[] mem[i]; } } return 0; } } int main(){return asbt::main();}

B. [COTS/CETS 2024] 双双决斗 Dvoboj

考虑如果没有修改,用 ST 表就非常舒服。
考虑暴力修改,需要修改所有覆盖了这个位置的区间,时间复杂度是 \(O(n)\) 的。
而如果只修改 \(\frac{\log n}{2}\) 层,时间复杂度就是 \(O(\sqrt{n})\) 的。查询时从上往下查,最多查到第 \(\frac{\log n}{2}\) 层,时间复杂度就也是 \(O(\sqrt{n})\) 的。于是就可以通过。

Code
复制代码
  • 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
#include<bits/stdc++.h> #define ll long long #define il inline using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=2e5+5; int n,m,blen,st[maxn][20]; il int Log(int x){ if(x==1){ return 0; } return Log(x>>1)+1; } il void upd(int l,int k){ if(k==blen){ return ; } if(l-(1<<k)>0){ st[l-(1<<k)][k+1]=abs(st[l-(1<<k)][k]-st[l][k]); upd(l-(1<<k),k+1); } if(l+(1<<(k+1))-1<=n){ st[l][k+1]=abs(st[l][k]-st[l+(1<<k)][k]); upd(l,k+1); } } il int query(int l,int k){ if(k<=blen){ return st[l][k]; } return abs(query(l,k-1)-query(l+(1<<(k-1)),k-1)); } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } int main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>st[i][0]; } blen=Log(n)>>1; for(int j=1;j<=blen;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ st[i][j]=abs(st[i][j-1]-st[i+(1<<(j-1))][j-1]); } } while(m--){ int opt,l,k; cin>>opt>>l>>k; if(opt==1){ st[l][0]=k; upd(l,0); } else{ cout<<query(l,k)<<"\n"; } } return 0; } } int main(){return asbt::main();}

C. 「SMOI-R1」Apple

考虑没有修改,高位前缀和就很舒服。如果修改就需要同时修改所有超集,时间复杂度是 \(O(2^n)\) 的。
考虑将一个二进制数拆成前后两段,修改时上传一段,查询时下查另一段,时间复杂度就是 \(O(q2^{\frac{n}{2}})\) 的。

Code
复制代码
  • 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<bits/stdc++.h> #define int long long #define il inline using namespace std; namespace asbt{ namespace cplx{bool begin;} namespace IO{ const int bufsz=1<<20; char ibuf[bufsz],*p1=ibuf,*p2=ibuf; #define getchar() (p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,bufsz,stdin),p1==p2)?EOF:*p1++) il int read(){ char ch=getchar(); while(ch<'0'||ch>'9'){ ch=getchar(); } int x=0; while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x; } #undef getchar char obuf[bufsz],*p3=obuf,s[50]; #define flush() (fwrite(obuf,1,p3-obuf,stdout),p3=obuf) #define putchar(ch) (p3==obuf+bufsz&&flush(),*p3++=(ch)) il void write(int x,bool typ=1){ int top=0; do{ s[++top]=x%10|48; x/=10; }while(x); while(top){ putchar(s[top--]); } putchar(typ?'\n':' '); } #undef putchar class Flush{ public: ~Flush(){ flush(); } }FL; #undef flush } using IO::read; using IO::write; const int maxn=(1<<10)+5,maxm=(1<<20)+5; int n,m,blen,bsan,b[maxm]; int qan[maxm],hou[maxm]; int a[maxn][maxn]; il void upd(int p,int v){ for(int i=hou[p];;i=(i+1)|hou[p]){ a[qan[p]][i]+=v; if(i==bsan){ return ; } } } il int query(int p){ int res=0; for(int i=qan[p];;i=(i-1)&qan[p]){ res+=a[i][hou[p]]; if(!i){ return res; } } } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } signed main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n>>m; blen=n>>1; bsan=(1<<blen)-1; for(int i=0;i<1<<n;i++){ cin>>b[i]; qan[i]=i>>blen; hou[i]=i&bsan; upd(i,b[i]); } while(m--){ int opt,p; cin>>opt>>p; if(opt==1){ cout<<query(p)<<"\n"; } else{ int v; cin>>v; upd(p,v-b[p]); b[p]=v; } } return 0; } } signed main(){return asbt::main();} /* 3 5 0 1 2 3 4 5 6 7 2 1 2 2 2 3 2 3 4 2 6 10 1 7 */

D. Till I Collapse

考虑当确定了 \(k\) 时,可以 \(O(n)\) 贪心去扫。
显然 \(k\) 递增时答案是不增的,同时答案小于 \(\frac{n}{k}\),所以不同的答案只有 \(O(\sqrt{n})\) 种。
于是对于 \(k<\sqrt{n}\) 暴力扫,对于 \(k\ge\sqrt{n}\) 暴力扫后二分有哪些 \(k\) 的答案是当前这个值。时间复杂度 \(O(n\sqrt{n}\log{n})\)

Code
复制代码
  • 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
#include<bits/stdc++.h> #define ll long long #define il inline using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=1e5+5; int n,a[maxn],blen,buc[maxn]; namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } int main(){ // ios::sync_with_stdio(0),cin.tie(0); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } blen=sqrt(n); for(int i=1,ans;i<=blen;i++){ ans=1; for(int j=1;j<=n;j++){ buc[j]=0; } for(int j=1,p=1,num=0;j<=n;j++){ if(buc[a[j]]++==0){ num++; } if(num>i){ ans++; for(int k=p;k<j;k++){ buc[a[k]]--; } num=1,p=j; } } cout<<ans<<" "; } // puts("666"); for(int i=blen+1,ans,l,r;i<=n;i++){ // cout<<i<<"\n"; ans=1; for(int j=1;j<=n;j++){ buc[j]=0; } for(int j=1,p=1,num=0;j<=n;j++){ if(buc[a[j]]++==0){ num++; } if(num>i){ ans++; for(int k=p;k<j;k++){ buc[a[k]]--; } num=1,p=j; } } // cout<<i<<" "<<ans<<"\n"; l=i,r=n; while(l<r){ int mid=(l+r+1)>>1,res=1; for(int j=1;j<=n;j++){ buc[j]=0; } for(int j=1,p=1,num=0;j<=n;j++){ if(buc[a[j]]++==0){ num++; } if(num>mid){ res++; for(int k=p;k<j;k++){ buc[a[k]]--; } num=1,p=j; } } if(res==ans){ l=mid; } else{ r=mid-1; } } // cout<<i<<" "<<l<<"\n"; for(int j=i;j<=l;j++){ cout<<ans<<" "; } i=l; } return 0; } } int main(){return asbt::main();}

E. Mr

根号分治,对于包含的边数 \(\le\sqrt{m}\) 的颜色暴力枚举所有点对存入 map,对于大于 \(\sqrt{m}\) 的颜色暴力扫所有查询。时间复杂度 \(O(m\sqrt{m}\log{m})\)

Code
复制代码
  • 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
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
#include<bits/stdc++.h> #define ll long long #define il inline #define pii pair<int,int> #define mp make_pair #define fir first #define sec second #define pb push_back using namespace std; namespace asbt{ namespace cplx{bool begin;} namespace IO{ const int bufsz=1<<20; char ibuf[bufsz],*p1=ibuf,*p2=ibuf; #define getchar() (p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,bufsz,stdin),p1==p2)?EOF:*p1++) il int read(){ char ch=getchar(); while(ch<'0'||ch>'9'){ ch=getchar(); } int x=0; while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x; } #undef getchar char obuf[bufsz],*p3=obuf,s[50]; #define flush() (fwrite(obuf,1,p3-obuf,stdout),p3=obuf) #define putchar(ch) (p3==obuf+bufsz&&flush(),*p3++=(ch)) il void write(int x){ int top=0; do{ s[++top]=x%10|48; x/=10; }while(x); while(top){ putchar(s[top--]); } putchar('\n'); } #undef putchar class Flush{ public: ~Flush(){ flush(); } }FL; #undef flush } using IO::read; using IO::write; const int maxn=1e5+5; int n,m,q,blen,ans[maxn]; int fa[maxn],sz[maxn],cun[maxn<<1]; pii wt[maxn]; vector<pii> e[maxn]; map<pii,int> wth; il int find(int x){ return x!=fa[x]?fa[x]=find(fa[x]):x; } il void merge(int u,int v){ u=find(u),v=find(v); if(u==v){ return ; } if(sz[u]<sz[v]){ swap(u,v); } sz[u]+=sz[v],fa[v]=u; } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } int main(){ n=read(),m=read(); // puts("666"); blen=sqrt(m); for(int i=1,u,v,w;i<=m;i++){ u=read(),v=read(),w=read(); e[w].pb(mp(u,v)); } // puts("666"); q=read(); for(int i=1,u,v;i<=q;i++){ u=read(),v=read(); if(u>v){ swap(u,v); } wt[i]=mp(u,v); } for(int i=1;i<=n;i++){ fa[i]=i,sz[i]=1; } for(int i=1,tot;i<=m;i++){ if(!e[i].size()){ continue; } tot=0; for(pii j:e[i]){ merge(j.fir,j.sec); cun[++tot]=j.fir; cun[++tot]=j.sec; } sort(cun+1,cun+tot+1); tot=unique(cun+1,cun+tot+1)-cun-1; if(e[i].size()>blen){ for(int j=1;j<=q;j++){ if(find(wt[j].fir)==find(wt[j].sec)){ ans[j]++; } } } else{ for(int j=1;j<=tot;j++){ for(int k=j+1;k<=tot;k++){ if(find(cun[j])==find(cun[k])){ wth[mp(cun[j],cun[k])]++; } } } } for(int j=1;j<=tot;j++){ fa[cun[j]]=cun[j]; sz[cun[j]]=1; } } // puts("666"); for(int i=1;i<=q;i++){ write(ans[i]+wth[mp(wt[i].fir,wt[i].sec)]); } return 0; } } int main(){return asbt::main();}

F. ycz的妹子

用线段树维护区间颜值和与妹子个数即可。时间复杂度 \(O(m\log{n})\)

Code
复制代码
  • 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
  • 111
  • 112
#include<bits/stdc++.h> #define int long long #define il inline #define lid id<<1 #define rid id<<1|1 using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=5e5+5; int n,m,a[maxn]; int sum[maxn<<2],sz[maxn<<2]; il void pushup(int id){ sum[id]=sum[lid]+sum[rid]; sz[id]=sz[lid]+sz[rid]; } il void build(int id,int l,int r){ if(l==r){ if(l<=n){ sum[id]=a[l],sz[id]=1; } return ; } int mid=(l+r)>>1; build(lid,l,mid); build(rid,mid+1,r); pushup(id); } il void upd1(int id,int l,int r,int p,int v){ if(l==r){ sum[id]-=v; return ; } int mid=(l+r)>>1; if(p<=mid){ upd1(lid,l,mid,p,v); } else{ upd1(rid,mid+1,r,p,v); } pushup(id); } il void upd2(int id,int l,int r,int p,int v){ if(l==r){ sum[id]=v,sz[id]=1; return ; } int mid=(l+r)>>1; if(p<=mid){ upd2(lid,l,mid,p,v); } else{ upd2(rid,mid+1,r,p,v); } pushup(id); } il void upd3(int id,int l,int r,int p){ if(l==r){ sum[id]=sz[id]=0; return ; } int mid=(l+r)>>1; if(sz[lid]>=p){ upd3(lid,l,mid,p); } else{ upd3(rid,mid+1,r,p-sz[lid]); } pushup(id); } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } signed main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; } build(1,1,5e5); while(m--){ char opt; cin>>opt; switch(opt){ case 'C':{ int p,v; cin>>p>>v; upd1(1,1,5e5,p,v); break; } case 'I':{ int p,v; cin>>p>>v; upd2(1,1,5e5,p,v); break; } case 'D':{ int p; cin>>p; upd3(1,1,5e5,p); break; } default:{ cout<<sum[1]<<"\n"; break; } } } return 0; } } signed main(){return asbt::main();}

G. Robin Hood Archery

考虑两个人的最优策略,一定都是先射击分高的。因此后手不可能赢,要求不输只能 \([l,r]\) 内每个分数都出现偶数次,才能平局。异或哈希即可。时间复杂度 \(O(n)\)

Code
复制代码
  • 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
#include<bits/stdc++.h> #define ll long long #define il inline #define ull unsigned ll using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=1e6+5; int T,n,m,a[maxn]; ull ha1[maxn],ha2[maxn]; ull hs1[maxn],hs2[maxn]; mt19937_64 rdsd(time(0)); namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } int main(){ ios::sync_with_stdio(0),cin.tie(0); for(int i=1;i<=1e6;i++){ while(!ha1[i]){ ha1[i]=rdsd(); } while(!ha2[i]){ ha2[i]=rdsd(); } } cin>>T; while(T--){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; hs1[i]=hs1[i-1]^ha1[a[i]]; hs2[i]=hs2[i-1]^ha2[a[i]]; } while(m--){ int l,r; cin>>l>>r; puts(hs1[r]==hs1[l-1]&&hs2[r]==hs2[l-1]?"YES":"NO"); } } return 0; } } int main(){return asbt::main();}

H. [THUPC 2017] 钦妹的玩具商店

分块,设块长为 \(B\),预处理 \(f_{l,r,x}\) 表示仅考虑 \([1,l]\cup[r,\frac{n}{B}]\) 中的玩具,花 \(x\) 元的最大愉悦度。询问时向 \(f_{bel_l-1,bel_r+1}\) 中加入 \(l\)\(r\) 所在块内的玩具即可。\(bel_l\) 表示 \(l\) 所在块。
使用二进制优化多重背包,分析时间复杂度:

  • 预处理 \(O(\frac{n^2m\log{n}}{B})\)
  • 询问 \(O(qmB\log{n})\)

\(B=\sqrt{n}\),时间复杂度为 \(O((n+q)m\sqrt{n}\log{n})\),空间复杂度 \(O(nm)\)

Code
复制代码
  • 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<bits/stdc++.h> #define int long long #define il inline using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=1e3+5,maxm=40,mod=1e8+7; int T,n,m,q,blen,bnum; int a[maxn],b[maxn],c[maxn]; int bel[maxn],st[maxm],ed[maxm]; struct DP{ int f[maxn]; il void init(){ for(int i=0;i<=m;i++){ f[i]=0; } } il int operator[](int x){ return f[x]; } il void upd(int x){ int a=asbt::a[x],b=asbt::b[x],c=asbt::c[x]; for(int i=1;i<=c;i<<=1){ for(int j=m;j>=i*a;j--){ f[j]=max(f[j],f[j-i*a]+i*b); } c-=i; } for(int i=m;i>=c*a;i--){ f[i]=max(f[i],f[i-c*a]+c*b); } } }dp[maxm][maxm]; il void solve(){ cin>>n>>m>>q; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=n;i++){ cin>>b[i]; } for(int i=1;i<=n;i++){ cin>>c[i]; } blen=sqrt(n); bnum=(n+blen-1)/blen; for(int i=1;i<=bnum;i++){ st[i]=ed[i-1]+1; ed[i]=min(ed[i-1]+blen,n); for(int j=st[i];j<=ed[i];j++){ bel[j]=i; } } for(int i=0;i<=bnum;i++){ if(!i){ dp[i][bnum+1].init(); } else{ dp[i][bnum+1]=dp[i-1][bnum+1]; for(int j=st[i];j<=ed[i];j++){ dp[i][bnum+1].upd(j); } } for(int j=bnum;j>i;j--){ dp[i][j]=dp[i][j+1]; for(int k=st[j];k<=ed[j];k++){ dp[i][j].upd(k); } } } int ans1=0,ans2=0; while(q--){ int l,r; cin>>l>>r; l=(l+ans1-1)%n+1; r=(r+ans1-1)%n+1; if(l>r){ swap(l,r); } DP ans=dp[bel[l]-1][bel[r]+1]; for(int i=st[bel[l]];i<l;i++){ ans.upd(i); } for(int i=ed[bel[r]];i>r;i--){ ans.upd(i); } ans1=ans2=0; for(int i=1;i<=m;i++){ ans1+=ans[i]; ans2^=ans[i]; } ans1%=mod; cout<<ans1<<" "<<ans2<<"\n"; } } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } signed main(){ // cout<<cplx::usdmem(); ios::sync_with_stdio(0),cin.tie(0); cin>>T; while(T--){ solve(); } return 0; } } signed main(){return asbt::main();}

I. [SNOI2017]一个简单的询问

\( \quad\sum{\operatorname{get}(l_1,r_1,x)\times\operatorname{get}(l_2,r_2,x)}\\ =\sum\operatorname{get}(1,l_1-1,x)\times\operatorname{get}(1,l_2-1,x)+\operatorname{get}(1,r_1,x)\times\operatorname{get}(1,r_2,x)-\operatorname{get}(1,l_1-1,x)\times\operatorname{get}(1,r_2,x)-\operatorname{get}(1,l_2-1,x)\times\operatorname{get}(1,r_1,x) \)
将一个询问拆成 \(4\) 个,莫队给 \(l\) 指针和 \(r\) 指针各开一个桶即可。

Code
复制代码
  • 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
#include<bits/stdc++.h> #define int long long #define il inline using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=5e4+5; int n,m,a[maxn],ans[maxn]; int blen,bel[maxn],tot; int bucl[maxn],bucr[maxn]; struct wnti{ int l,r,id; wnti(int l=0,int r=0,int id=0):l(l),r(r),id(id){} il bool operator<(const wnti &x)const{ if(bel[l]==bel[x.l]){ return bel[l]&1?r>x.r:r<x.r; } return l<x.l; } }wt[maxn<<2]; namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } signed main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } cin>>m; for(int i=1,l1,r1,l2,r2;i<=m;i++){ cin>>l1>>r1>>l2>>r2; wt[++tot]=wnti(l1-1,l2-1,i); wt[++tot]=wnti(r1,r2,i); wt[++tot]=wnti(l1-1,r2,-i); wt[++tot]=wnti(l2-1,r1,-i); } blen=n/sqrt(tot)+1; for(int i=0;i<=n;i++){ bel[i]=i/blen; } sort(wt+1,wt+tot+1); int l=0,r=0,res=0; for(int i=1;i<=tot;i++){ while(l<wt[i].l){ bucl[a[++l]]++; res+=bucr[a[l]]; } while(r<wt[i].r){ bucr[a[++r]]++; res+=bucl[a[r]]; } while(l>wt[i].l){ res-=bucr[a[l]]; bucl[a[l--]]--; } while(r>wt[i].r){ res-=bucl[a[r]]; bucr[a[r--]]--; } if(wt[i].id>0){ ans[wt[i].id]+=res; } else{ ans[-wt[i].id]-=res; } } for(int i=1;i<=m;i++){ cout<<ans[i]<<"\n"; } return 0; } } signed main(){return asbt::main();}

J. XOR and Favorite Number

考虑如何计算区间 \([l,r]\) 的异或和,显然做一个前缀异或和 \(pre\),答案即为 \(pre_r\oplus pre_{l-1}\)。那么在进行莫队时,设新增了一个 \(pre\) 值为 \(x\) 的点,那么对答案的贡献即为当前统计的 \(x\oplus k\) 的数量。时间复杂度 \(O(n\sqrt{m})\)

Code
复制代码
  • 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
#include<bits/stdc++.h> #define int long long #define il inline using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=(1<<20)+5; int n,m,k,blen; int a[maxn],buc[maxn]; int ans[maxn],bel[maxn]; struct wnti{ int l,r,id; il bool operator<(const wnti &x)const{ if(bel[l]==bel[x.l]){ return bel[l]&1?r>x.r:r<x.r; } return l<x.l; } }wt[maxn]; il void add(int x,int &res){ res+=buc[x^k]; buc[x]++; } il void del(int x,int &res){ buc[x]--; res-=buc[x^k]; } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } signed main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n>>m>>k; for(int i=1;i<=n;i++){ cin>>a[i]; a[i]^=a[i-1]; } for(int i=1;i<=m;i++){ cin>>wt[i].l>>wt[i].r; wt[i].id=i; } blen=max(n/sqrt(m),1.0); for(int i=1;i<=n;i++){ bel[i]=i/blen; } sort(wt+1,wt+m+1); int l=1,r=0,res=0; buc[0]=1; for(int i=1;i<=m;i++){ // cout<<wt[i].l<<" "<<wt[i].r<<" "<<wt[i].id<<"\n"; while(l>wt[i].l){ add(a[--l-1],res); } while(r<wt[i].r){ add(a[++r],res); } // cout<<res<<"\n"; while(l<wt[i].l){ del(a[l++-1],res); } while(r>wt[i].r){ del(a[r--],res); } ans[wt[i].id]=res; } for(int i=1;i<=m;i++){ cout<<ans[i]<<"\n"; } return 0; } } signed main(){return asbt::main();} /* 50 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 35 3 35 */

K. String Set Queries

考虑所有集合内的字符串的不同长度不会超过 \(\sqrt{\sum|s_i|}\),因此直接枚举所有长度,哈希即可。时间复杂度 \(O(n\sqrt{n}\log{n})\)

Code
复制代码
  • 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
#include<bits/stdc++.h> #define ll long long #define il inline #define ull unsigned ll #define mp make_pair #define pii pair<int,int> using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=3e5+5; const ull bas1=13331; const ll bas2=13327,mod2=1e9+7; int n; ull ha1[maxn],pw1[maxn]; ll ha2[maxn],pw2[maxn]; char s[maxn]; map<int,int> clen; map<pair<ull,ll>,int> cha; il ull gha1(int l,int r){ return ha1[r]-ha1[l-1]*pw1[r-l+1]; } il ll gha2(int l,int r){ return (ha2[r]-ha2[l-1]*pw2[r-l+1]%mod2+mod2)%mod2; } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } int main(){ pw1[0]=pw2[0]=1; for(int i=1;i<=3e5;i++){ pw1[i]=pw1[i-1]*bas1; pw2[i]=pw2[i-1]*bas2%mod2; } scanf("%d",&n); while(n--){ int opt,len; scanf("%d %s",&opt,s+1); len=strlen(s+1); switch(opt){ case 1:{ ull ha1=0; ll ha2=0; for(int i=1;i<=len;i++){ ha1=ha1*bas1+s[i]; ha2=(ha2*bas2+s[i])%mod2; } clen[len]++; cha[mp(ha1,ha2)]++; break; } case 2:{ ull ha1=0; ll ha2=0; for(int i=1;i<=len;i++){ ha1=ha1*bas1+s[i]; ha2=(ha2*bas2+s[i])%mod2; } if(--clen[len]==0){ clen.erase(len); } if(--cha[mp(ha1,ha2)]==0){ cha.erase(mp(ha1,ha2)); } break; } default:{ int res=0; for(int i=1;i<=len;i++){ ha1[i]=ha1[i-1]*bas1+s[i]; ha2[i]=(ha2[i-1]*bas2+s[i])%mod2; } for(pii i:clen){ for(int l=1,r=i.first;r<=len;l++,r++){ res+=cha[mp(gha1(l,r),gha2(l,r))]; } } printf("%d\n",res); fflush(stdout); break; } } } return 0; } } int main(){return asbt::main();}
posted @   zhangxy__hp  阅读(17)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开