A. Box Game
注意到局面总数不超过$50000$,而且每次操作都会改变石子的奇偶性,因此按奇偶可以将状态建成二分图,然后求出最大匹配。
如果状态数是偶数,那么先手必胜,策略就是每次走匹配边,那么对手不能通过匹配边走回来,因此所有匹配边你都能走掉。
如果状态数是奇数,那么如果此时有奇数个石子,也是先手必胜,因为最后对手会遭遇怎么走都会回到以前走过的局面的困境。
选择完先后手之后,每次按匹配边走下去即可。
B. Circle of Stones
首先将环倍长,破环成链,那么剩下的子串要满足相邻字符不同且首尾字符不同。
通过双指针求出每一段极长的子串,满足相邻字符不同,设这一段长度为$len$,从$2$到$len$枚举剩下的串的长度$L$,若该子串长度为$len-L+1$的前后缀不能完全匹配,则说明存在距离为$L-1$的位置不同,也就能充当首尾,Hash判断即可。
时间复杂度$O(n)$。
#include<cstdio> #include<cstring> typedef long long ll; const int N=2000010,D=233,P=1000000009; int C,n,m,i,j,k,len;char a[N],ans[N];ll pow[N],f[N]; inline ll hash(int l,int r){return((f[r]-f[l-1]*pow[r-l+1])%P+P)%P;} int main(){ for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*D%P; while(~scanf("%s",a+1)){ n=strlen(a+1);m=n+n; for(i=1;i<=n;i++)a[i+n]=a[i]; for(i=1;i<=m;i++)f[i]=(f[i-1]*D+a[i])%P; for(i=0;i<n;i++)ans[i]='0'; for(i=1;i<=m;i=j+1){ for(j=i;j<m&&a[j]!=a[j+1];j++); len=j-i+1; for(k=2;k<=len&&k<=n;k++)if(hash(i,i+len-k)!=hash(j-len+k,j))ans[n-k]='1'; } for(printf("Case %d: ",++C),i=0;i<n-1;i++)putchar(ans[i]);puts("1"); } return 0; }
C. Expression with Sets
留坑。
D. Heating System
留坑。
E. Islands
留坑。
F. Longest Two Graphs Common String
设$f[i][j][0]$表示选出的路径里,第一张图中最后一个点是$i$,第二张图中最后一个点是$j$的最大长度。
设$f[i][j][1]$表示选出的路径里,第一张图中最后一个点再往后乱走一步到了$i$,第二张图中最后一个点是$j$的最大长度。
则对于$f[i][j][0]$,只需要枚举指向$j$的边,用$f[i][j'][1]$转移;对于$f[i][j][1]$,只需要枚举指向$i$的边,用$f[i'][j][0]$转移。
时间复杂度$O(n(n+m))$。
#include<cstdio> const int N=505,M=4010; int T,n1,n2,m,i,j,k,flag,ans,X,Y,q[N*N][2]; int f[N][N][2],pre[N][N][2]; bool v[N][N][2],vis[N][N][2]; struct G{ int n,g[N],v[M],nxt[M],ed; int i,x,y; char a[N]; void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void init(int _n,int m){ n=_n; scanf("%s",a+1); for(ed=0,i=1;i<=n;i++)g[i]=0; while(m--)scanf("%d%d",&x,&y),add(y,x); } }G1,G2; void dp(int x,int y,int z){ if(vis[x][y][z])flag=1; if(flag)return; if(v[x][y][z])return; vis[x][y][z]=v[x][y][z]=1; int&t=f[x][y][z],&p=pre[x][y][z]; t=-1,p=0; if(z==0){ if(G1.a[x]==G2.a[y]){ t=0; for(int i=G2.g[y];i;i=G2.nxt[i]){ int k=G2.v[i]; dp(x,k,z^1); if(f[x][k][z^1]>t)t=f[x][k][z^1],p=k; } if(~t)t++; } }else{ for(int i=G1.g[x];i;i=G1.nxt[i]){ int k=G1.v[i]; dp(k,y,z^1); if(f[k][y][z^1]>t)t=f[k][y][z^1],p=k; } } vis[x][y][z]=0; } int main(){ while(~scanf("%d%d",&n1,&m)){ G1.init(n1,m); scanf("%d%d",&n2,&m); G2.init(n2,m); for(i=1;i<=n1;i++)for(j=1;j<=n2;j++)for(k=0;k<2;k++)v[i][j][k]=vis[i][j][k]=0; ans=flag=0; for(i=1;i<=n1;i++)for(j=1;j<=n2;j++){ dp(i,j,0); if(f[i][j][0]>ans)ans=f[i][j][0],X=i,Y=j; } printf("Case %d: ",++T); if(flag)puts("-1");else{ printf("%d ",ans); for(i=ans;i;i--){ q[i][0]=X,q[i][1]=Y; Y=pre[X][Y][0]; X=pre[X][Y][1]; } for(i=1;i<=ans;i++)printf("%d%c",q[i][0],i<ans?' ':' '); for(i=1;i<=ans;i++)printf("%d%c",q[i][1],i<ans?' ':' '); } } return 0; }
G. Lyndon Words
找规律构造,可以$O(n)$生成字典序下一个,暴力生成出字典序前$r$小的所有串即可。
时间复杂度$O(nr)$。
H. Temperature
状压DP。
时间复杂度$O(n2^n)$。
I. Editor 2
留坑。
J. Tourist Problem
留坑。
K. Ant versus Woodpecker
显然答案就是虚树上度数$>1$的点的深度的最大值,用ETT维护dfs序并支持查询lca即可。
时间复杂度$O((m+sum k)log n)$。
#include<cstdio> #include<algorithm> #include<set> using namespace std; const int N=400010; int C,n,m,i,x,g[N],Nxt[N]; int vis[N],a[N],dfn[N],deg[N],t,q[N]; int id[N]; int d[N],st[N],en[N],pre[N],nxt[N],val[N],md[N],size[N],son[N][2],f[N],tot,root; set<int>T; inline void up(int x){ md[x]=val[x]; size[x]=1; if(son[x][0]){ if(d[md[son[x][0]]]<d[md[x]])md[x]=md[son[x][0]]; size[x]+=size[son[x][0]]; } if(son[x][1]){ if(d[md[son[x][1]]]<d[md[x]])md[x]=md[son[x][1]]; size[x]+=size[son[x][1]]; } } inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x; if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y); } inline void splay(int x,int w){ while(f[x]!=w){ int y=f[x]; if(f[y]!=w){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } if(!w)root=x; up(x); } inline int getrank(int x){ splay(x,0); return size[son[x][0]]; } inline void addnode(int x,int y){//x father is y d[x]=d[y]+1; int z=nxt[st[y]]; splay(st[y],0); splay(z,root); son[z][0]=++tot; val[tot]=x; f[tot]=z; st[x]=tot; id[tot]=x; son[st[x]][1]=++tot; f[tot]=st[x]; val[tot]=y; en[x]=tot; up(tot); up(st[x]); up(z); up(root); nxt[root]=st[x]; nxt[st[x]]=en[x]; nxt[en[x]]=z; pre[z]=en[x]; pre[en[x]]=st[x]; pre[st[x]]=root; } void dfsdel(int x){ if(!x)return; if(id[x])T.insert(id[x]); dfsdel(son[x][0]); dfsdel(son[x][1]); } inline void delsubtree(int x){ splay(pre[st[x]],0); splay(nxt[en[x]],root); int z=son[root][1]; nxt[root]=z; pre[z]=root; dfsdel(son[z][0]); son[z][0]=0; up(z); up(root); } void show(int x){ if(!x)return; show(son[x][0]); printf("%d ",val[x]); show(son[x][1]); } inline int lca(int x,int y){ if(x==y)return x; if(x==1||y==1)return 1; if(getrank(st[x])>getrank(st[y]))swap(x,y); splay(pre[st[x]],0); splay(nxt[st[y]],root); return md[son[son[root][1]][0]]; } int build(int l,int r,int fa){ int mid=(l+r)>>1; f[mid]=fa; if(l<mid)son[mid][0]=build(l,mid-1,mid); if(r>mid)son[mid][1]=build(mid+1,r,mid); up(mid); return mid; } inline bool cmp(int x,int y){return dfn[x]<dfn[y];} void dfs(int x){ for(int i=g[x];i;i=Nxt[i]){ d[i]=d[x]+1; st[i]=++tot; val[tot]=i; dfs(i); en[i]=++tot; val[tot]=x; } } inline int getid(){ int x=*T.begin(); T.erase(x); return x; } int main(){ while(~scanf("%d",&n)){ st[1]=1; val[1]=1; tot=1; for(i=2;i<=n;i++){ scanf("%d",&x); Nxt[i]=g[x]; g[x]=i; } dfs(1); en[1]=++tot; val[tot]=1; for(i=1;i<tot;i++){ pre[i+1]=i; nxt[i]=i+1; } for(i=1;i<=n;i++)id[st[i]]=i; root=build(1,tot,0); int mm; scanf("%d",&mm); int lim=n+mm; T.clear(); for(i=n+1;i<=n+mm;i++)T.insert(i); int last=0; printf("Case %d:",++C); while(mm--){ char op[5]; scanf("%s",op); if(op[0]=='+'){ int x; scanf("%d",&x); int y=getid(); x+=last; addnode(y,x); } if(op[0]=='-'){ int x; scanf("%d",&x); delsubtree(x); } if(op[0]=='?'){ //show(root);puts(""); scanf("%d",&m); int cnt=1; a[1]=1; vis[1]=1; dfn[1]=getrank(st[1]); while(m--){ scanf("%d",&x); if(!vis[x]){ a[++cnt]=x,vis[x]=1; dfn[x]=getrank(st[x]); } } //for(i=1;i<=cnt;i++)printf("%d ",a[i]);puts(""); sort(a+1,a+cnt+1,cmp); int now=cnt; for(i=1;i<cnt;i++)if(!vis[x=lca(a[i],a[i+1])]){ vis[a[++now]=x]=1; dfn[x]=getrank(st[x]); } sort(a+1,a+now+1,cmp); //for(i=1;i<=now;i++)printf("%d ",a[i]);puts(""); last=-1; for(q[t=1]=1,i=2;i<=now;q[++t]=a[i++]){ while(lca(a[i],q[t])!=q[t])t--; deg[q[t]]++; if(deg[q[t]]>1)last=max(last,d[q[t]]); //printf("edge %d %d ",q[t],a[i]); } printf(" %d",last); for(i=1;i<=now;i++)vis[a[i]]=deg[a[i]]=0; } } puts(""); for(i=1;i<=lim;i++)st[i]=en[i]=d[i]=g[i]=0; for(i=0;i<=tot+1;i++)id[i]=pre[i]=nxt[i]=val[i]=md[i]=size[i]=son[i][0]=son[i][1]=f[i]=0; tot=root=0; } return 0; }