十二省联考 2019
day1 T1:
异或之
注意scanf输入u32的方式
#include <bits/stdc++.h> #define rep(a,b,i) for(int i=a;i<=b;++i) #define per(a,b,i) for(int i=a;i>=b;--i) using namespace std; typedef long long s64; typedef unsigned long long u64; typedef unsigned int u32; typedef pair<u32,int> pii; const int M=5e5+5; int n,m; u32 a[M]; int rank_[M]; set <pii> q; struct sp { sp *ch[2]; int size; }*root,*null; void insert(sp *&g,u32 x,int c) { if(g==null) { g=new sp(); g->size=0; g->ch[0]=g->ch[1]=null; } ++g->size; if(c==-1) return; insert(g->ch[x>>c&1],x,c-1); } u32 query(u32 x,int y) { u32 ans=0; sp *t=root; per(31,0,i) { bool c=(x>>i&1)^1; ans+=(u32)1<<i; if(t->ch[c]->size<y) ans-=(u32)1<<i,y-=t->ch[c]->size,c^=1; t=t->ch[c]; } return ans; } u32 get_() { auto x=q.begin(); u32 ans=-x->first; int p=x->second; q.erase(x); if(rank_[p]<n) ++rank_[p],q.insert((pii){-query(a[p],rank_[p]),p}); return ans; } int main() { //freopen("a.in","r",stdin); scanf("%d%d",&n,&m); rep(1,n,i) scanf("%u",a+i),a[i]^=a[i-1]; null=new sp(); null->size=0; null->ch[0]=null->ch[1]=null; root=new sp(); root->size=0; root->ch[0]=root->ch[1]=null; rep(0,n,i) insert(root,a[i],31); rep(0,n,i) rank_[i]=1,q.insert((pii){-query(a[i],1),i}); s64 ans=0; rep(1,m,i) { u32 x=get_();get_(); ans+=x; } cout<<ans<<endl; }
day1 T2:
显然建图
后缀数组可以sort字符串后线段树优化,但是不好写
后缀自动机的fail树完全满足这个条件,只需要拆点就行了
#include <bits/stdc++.h> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define rep(i,a,b) for(int i=a;i<=b;++i) #define per(i,a,b) for(int i=a;i>=b;--i) using namespace std; typedef long long s64; typedef unsigned long long u64; typedef unsigned int u32; typedef pair<u32,int> pii; const int M=1e6+5; int len,n,m,t,x,y; char s[M]; int las,cnt,mx[M],fa[M][20],nxt[M][26]; int l[M],r[M],q[M],du[M],val[M],pos[M]; s64 f[M]; vector <int> to[M],cc[M]; void extend_(int c) { int p=las,np=las=++cnt; mx[np]=mx[p]+1; while (p&&!nxt[p][c]) nxt[p][c]=np,p=fa[p][0]; if(!p) fa[np][0]=1; else { int q=nxt[p][c]; if(mx[q]==mx[p]+1) fa[np][0]=q; else { int nq=++cnt; fa[nq][0]=fa[q][0]; memcpy(nxt[nq],nxt[q],sizeof(nxt[q])); mx[nq]=mx[p]+1,fa[q][0]=fa[np][0]=nq; while (nxt[p][c]==q) nxt[p][c]=nq,p=fa[p][0]; } } } void dfs(int x) { rep(i,1,19) fa[x][i]=fa[fa[x][i-1]][i-1]; for(auto v:to[x]) dfs(v); } int find(int l,int r) { int ans=pos[r]; per(i,19,0) if(mx[fa[ans][i]]>=r-l+1) ans=fa[ans][i]; return ans; } bool check() { int h=1,tail_=0; memset(du,0,sizeof(du)); rep(i,1,cnt+n) for(auto v:to[i]) ++du[v]; rep(i,1,cnt+n) if(du[i]==0) q[++tail_]=i; while (h<=tail_) { int r=q[h++]; for(auto v:to[r]) { --du[v]; if(!du[v]) q[++tail_]=v; } } rep(i,1,cnt+n) if(du[i]) return 0; return 1; } int main() { //freopen("a.in","r",stdin); int test_; scanf("%d",&test_); while (test_--) { //init las=cnt=1; memset(fa,0,sizeof(fa)); memset(nxt,0,sizeof(nxt)); scanf("%s",s+1); len=strlen(s+1); per(i,len,1) extend_(s[i]-'a'),pos[len-i+1]=las; rep(i,1,cnt) if(fa[i][0]) to[fa[i][0]].push_back(i); dfs(1); rep(i,1,cnt) to[i].clear(); scanf("%d",&n); rep(i,1,n) { scanf("%d%d",l+i,r+i); swap(l[i],r[i]); l[i]=len-l[i]+1,r[i]=len-r[i]+1; int x=find(l[i],r[i]); if(mx[x]!=r[i]-l[i]+1) cc[x].push_back(r[i]-l[i]+1); } scanf("%d",&m); rep(i,1,m) { scanf("%d%d",l+n+i,r+n+i); swap(l[n+i],r[n+i]); l[n+i]=len-l[n+i]+1,r[n+i]=len-r[n+i]+1; } scanf("%d",&t); rep(i,1,t) { scanf("%d%d",&x,&y); l[n+m+i]=x,r[n+m+i]=y; y+=n; x+=cnt+n; int c=find(l[y],r[y]); if(mx[fa[c][0]]+1!=r[y]-l[y]+1) cc[c].push_back(r[y]-l[y]); } rep(i,1,cnt) { sort(cc[i].begin(),cc[i].end()); int pre=-1; for(auto v:cc[i]) { if(v==pre) continue; pre=v; ++cnt; fa[cnt][0]=fa[i][0]; fa[i][0]=cnt; mx[cnt]=v; } } rep(i,1,cnt) if(fa[i][0]) to[fa[i][0]].push_back(i); dfs(1); rep(i,1,n) { int x=find(l[i],r[i]); if(mx[x]!=r[i]-l[i]+1) { cout<<mx[fa[x][0]]+1<<" "<<mx[x]<<" "<<r[i]-l[i]+1<<endl; cout<<"wrong!"<<endl; while (1); } to[x].push_back(cnt+i); } rep(i,1,t) { int x=l[n+m+i],y=r[n+m+i]; int p=find(l[n+y],r[n+y]); to[cnt+x].push_back(p); } memset(val,0,sizeof(val)); rep(i,1,n) val[cnt+i]=r[i]-l[i]+1; if(!check()) puts("-1"); else { s64 ans=0; per(i,n+cnt,1) { int r=q[i]; s64 Max=0; for(auto v:to[r]) Max=max(Max,f[v]); f[r]=val[r]+Max; ans=max(ans,f[r]); } printf("%lld\n",ans); } rep(i,1,cnt+n) to[i].clear(),cc[i].clear(); } }
day2 T1:
最重要的思路就是$k=0$阵营和派系没有关系直接分开dp
$k>0$就直接dp这30个剩下按照$k=0$做就行了
#include <bits/stdc++.h> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define rep(i,a,b) for(int i=a;i<=b;++i) #define per(i,a,b) for(int i=a;i>=b;--i) using namespace std; typedef long long s64; typedef unsigned long long u64; typedef unsigned int u32; typedef pair<u32,int> pii; const int M=2.5e3+5; const int mod=998244353; int n,m,K; int C0,C1,D0,D1; int A[2][2][M][305],B[2][2][M],C[2][M]; bool vis[M]; struct node { int s,p,b; bool operator <(const node &x) const { return b<x.b; } }a[M]; inline void inc(int &x,int y) {x+=y,x-=x>=mod?mod:0;} int main() { //freopen("a.in","r",stdin); int test_; scanf("%d",&test_); while (test_--) { memset(vis,0,sizeof(vis)); int sum=0; scanf("%d%d",&n,&m); scanf("%d%d%d%d",&C0,&C1,&D0,&D1); rep(i,1,n) scanf("%d%d",&a[i].b,&a[i].s),a[i].p=-1,sum+=a[i].s; scanf("%d",&K); rep(i,1,K) { int x,y; scanf("%d%d",&x,&y); vis[a[x].b]=1,a[x].p=y; } sort(a+1,a+n+1); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(C,0,sizeof(C)); int opt[4]={0}; A[0][0][0][0]=1; B[0][0][0]=1; C[0][0]=1; for(int l=1,r;l<=n;l=r+1) { r=l; while (a[r+1].b==a[r].b) ++r; rep(i,l,r) { if(a[i].p!=-1) continue; memset(C[opt[3]^1],0,sizeof(C[0])); rep(j,0,D0) if(C[opt[3]][j]) { inc(C[opt[3]^1][j],C[opt[3]][j]); if(j+a[i].s<=D0) inc(C[opt[3]^1][j+a[i].s],C[opt[3]][j]); } opt[3]^=1; } if(!vis[a[l].b]) { rep(i,l,r) { memset(B[opt[2]^1],0,sizeof(B[0])); rep(j,0,C0) { //0 if(j>=a[i].s) { inc(B[opt[2]^1][0][j],B[opt[2]][0][j-a[i].s]); if(i==l) inc(B[opt[2]^1][0][j],B[opt[2]][1][j-a[i].s]); } //1 inc(B[opt[2]^1][1][j],B[opt[2]][1][j]); if(i==l) inc(B[opt[2]^1][1][j],B[opt[2]][0][j]); } opt[2]^=1; } } else { int pre[2]={-1,0}; rep(i,l,r) { if(a[i].p!=-1) { memset(A[opt[1]^1],0,sizeof(A[0])); rep(j,0,C0) per(k,min(D0,300),0) { int sum[2]={A[opt[1]][0][j][k],A[opt[1]][1][j][k]}; if(!sum[0]&&!sum[1]) continue; rep(u,0,3) { if(u==a[i].p) continue; bool t0=u>>1,t1=u&1; int x=j+(t0^1)*a[i].s,y=k+(t1^1)*a[i].s; if(x<=C0&&y<=D0) { inc(A[opt[1]^1][t0][x][y],sum[t0]); if(pre[0]==-1) inc(A[opt[1]^1][t0][x][y],sum[t0^1]); } } } pre[0]=1; opt[1]^=1; } else pre[1]+=a[i].s; } memset(A[opt[1]^1],0,sizeof(A[0])); per(j,C0,pre[1]) memcpy(A[opt[1]][0][j],A[opt[1]][0][j-pre[1]],sizeof(A[opt[1]][0][j])); per(j,pre[1],0) memset(A[opt[1]][0][j],0,sizeof(A[opt[1]][0][j])); } } int ans=0; rep(i,0,C0) { inc(B[opt[2]][1][i],B[opt[2]][0][i]); if(i) inc(B[opt[2]][1][i],B[opt[2]][1][i-1]); } rep(i,1,D0) inc(C[opt[3]][i],C[opt[3]][i-1]); rep(i,0,1) rep(j,0,C0) per(k,min(300,D0),0) if(A[opt[1]][i][j][k]) { int c=A[opt[1]][i][j][k]; int sel=B[opt[2]][1][C0-j]; if(sum-j-C1>0) inc(sel,mod-B[opt[2]][1][sum-j-C1-1]); c=1ll*c*sel%mod; sel=C[opt[3]][D0-k]; if(sum-k-D1>0) inc(sel,mod-C[opt[3]][sum-k-D1-1]); inc(ans,1ll*c*sel%mod); } cout<<ans<<endl; } //cout<<(double)clock()/CLOCKS_PER_SEC<<endl; }