B:显然即相当于能否找一条有长度为奇数的路径使得终点出度为0。如果没有环直接dp即可。有环的话可以考虑死了的spfa,由于每个点我们至多只需要让其入队两次,复杂度变成了优秀的O(kE)。事实上就是拆点。方案的输出在spfa过程中记录即可。然后判一下由起点是否能走进一个环,若可以至少是平局。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,p[N],f[N],from[N][2],q[N],degree[N],dfn[N],size[N],t,cnt; bool flag[N]; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;degree[x]++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} int inc(int &x){x++;if (x>n+1) x-=n+1;return x;} void spfa(int S) { f[S]=1;q[1]=S; int head=0,tail=1; do { int x=q[inc(head)];flag[x]=0; for (int i=p[x];i;i=edge[i].nxt) if (f[edge[i].to]<3&&(f[x]==3||f[x]==f[edge[i].to]||f[edge[i].to]==0)) { if (f[x]==3) { if (f[edge[i].to]==0) from[edge[i].to][0]=from[edge[i].to][1]=x; else from[edge[i].to][(3^f[edge[i].to])==2]=x; f[edge[i].to]=3; } else f[edge[i].to]|=3^f[x],from[edge[i].to][(3^f[x])==2]=x; if (!flag[edge[i].to]) { flag[edge[i].to]=1; q[inc(tail)]=edge[i].to; } } }while (head!=tail); } void dfs1(int k) { dfn[k]=++cnt;size[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (!dfn[edge[i].to]) dfs1(edge[i].to),size[k]+=size[edge[i].to]; } bool dfs(int k) { flag[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (flag[edge[i].to]){if (dfn[edge[i].to]<=dfn[k]&&dfn[edge[i].to]+size[edge[i].to]>dfn[k]) return 1;} else if (dfs(edge[i].to)) return 1; return 0; } void print(int k,int op) { if (k==0) return; print(from[k][op],op^1); printf("%d ",k); } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(); for (int i=1;i<=n;i++) { int x=read(); while (x--) addedge(i,read()); } int S;spfa(S=read()); for (int i=1;i<=n;i++) if (!degree[i]&&(f[i]&2)) { cout<<"Win"<<endl; print(i,1); return 0; } dfs1(S);memset(flag,0,sizeof(flag)); if (dfs(S)) cout<<"Draw";else cout<<"Lose"; return 0; //NOTICE LONG LONG!!!!! }
C:显然字符集不同时无解。考虑我们已经满足了目标字符串的前i位,现在要将第i+1位也放在正确的位置。将当前串拆成abxy四部分,a是已经安排好的位置,x是i+1位的当前位置。把已经满足的位置放在字符串末尾,即形如bxya。移动ya得到aybx(a倒序),可以直接接上x得到ayxb(原x和a合并),直接翻转整个串就回到了原状态bxya。于是我们用3步放好了一位,就做完了。sol里2.5n的也区别不大但懒得管了。构造全靠凑,原本把已经满足的位置放在了开头,结果怎么捣鼓都是3.5n,放在末尾简直一眼就出来了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 2010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,cnt[N]; char a[N],b[N],c[N]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(); cin>>(a+1)>>(b+1); for (int i=1;i<=n;i++) cnt[a[i]]++; for (int i=1;i<=n;i++) cnt[b[i]]--; for (int i=1;i<=200;i++) if (cnt[i]) {cout<<-1;return 0;} cout<<n*3<<endl; for (int i=1;i<=n;i++) { int p=0; for (int j=1;j<=n;j++) if (a[j]==b[i]) {p=j;break;} cout<<n-p<<' '<<1<<' '<<n<<' '; reverse(a+p+1,a+n+1); for (int j=p;j<=n;j++) c[j-p+1]=a[j]; for (int j=1;j<p;j++) c[n-p+1+j]=a[j]; for (int j=1;j<=n;j++) a[j]=c[j]; reverse(a+1,a+n+1); } return 0; //NOTICE LONG LONG!!!!! }
D:考虑dp出每堵墙最早在什么位置可以被破坏。要将其破坏要么得破坏其正前方的墙,要么得绕到其正前方的墙后面(显然这种情况绕到后面恰好一格最优)。第一种情况可以直接转移而来,第二种情况还需要求到达某个位置时最快还要多久才能开枪。这个东西同样考虑dp,要到这个位置要么从该行直接冲过来,要么从另一行绕过来。第一种情况考虑其正前方是否有墙,没有直接转移,有则用上面的dp值转移;第二种情况类似考虑该列另一位置有没有墙即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<cassert> using namespace std; #define ll long long #define N 2000010 #define inf 1010000000 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m1,m2,t,a[N],b[N],v[N],pre[N][2],f[N][2],g[N][2],from[N][2][2],u,p[N],q[N][2]; bool flag[N][2]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),m1=read(),m2=read(),t=read(); for (int i=1;i<=m1;i++) v[++u]=a[i]=read(),v[++u]=a[i]+1; for (int i=1;i<=m2;i++) v[++u]=b[i]=read(),v[++u]=b[i]+1; v[++u]=1; sort(v+1,v+u+1); u=unique(v+1,v+u+1)-v-1; for (int i=1;i<=m1;i++) flag[a[i]=lower_bound(v+1,v+u+1,a[i])-v][0]=1; for (int i=1;i<=m2;i++) flag[b[i]=lower_bound(v+1,v+u+1,b[i])-v][1]=1; for (int i=1;i<=u;i++) { f[i][0]=f[i][1]=g[i][0]=g[i][1]=inf; if (flag[i-1][0]) pre[i][0]=i-1;else pre[i][0]=pre[i-1][0]; if (flag[i-1][1]) pre[i][1]=i-1;else pre[i][1]=pre[i-1][1]; } flag[0][0]=flag[0][1]=1;f[0][0]=f[0][1]=t;g[0][0]=g[0][1]=0; for (int i=1;i<=u;i++) { int tmp[2]={0,1};if (flag[i][1]) swap(tmp[0],tmp[1]); for (int qwq=0,j=tmp[qwq];qwq<2;qwq++,j=tmp[qwq]) if (flag[i][j]) { int x=pre[i][j]; g[i][j]=g[x][j]+t; if (g[i][j]>=v[i]) g[i][j]=inf; else { f[i][j]=max(0,t-(v[i]-g[i][j])); from[i][j][0]=x,from[i][j][1]=j; } x++; if (x!=i&&f[x][j]<v[i]-v[x]&&max(0,f[x][j]-v[i]+v[x]+t)<=f[i][j]) { f[i][j]=max(0,f[x][j]-v[i]+v[x]+t); g[i][j]=min(g[i][j],v[x]+f[x][j]); from[i][j][0]=x,from[i][j][1]=j; } f[i][j]=min(f[i][j],inf); } else { int x=max(0,f[i-1][j]-v[i]+v[i-1]),y=flag[i][j^1]?f[i][j^1]:max(0,f[i-1][j^1]-v[i]+v[i-1]); if (x<=y) { f[i][j]=x;from[i][j][0]=i-1,from[i][j][1]=j; } else { f[i][j]=y;from[i][j][0]=i,from[i][j][1]=j^1; } f[i][j]=min(f[i][j],inf); } } if (min(f[u][0],f[u][1])>n+59) {cout<<"No";return 0;} else { cout<<"Yes"<<endl; int x=u,y=0;if (f[x][y]>n+59) y^=1;//cout<<x<<' '<<y<<endl; int topp=0,topq=0; while (x) { if (from[x][y][1]!=y) p[++topp]=from[x][y][0]; if (flag[x][y]) q[++topq][0]=g[x][y],q[topq][1]=y+1; int u=from[x][y][0],v=from[x][y][1]; x=u,y=v; } if (y==1) p[++topp]=0; cout<<topp<<endl; for (int i=topp;i>=1;i--) printf("%d ",v[p[i]]);cout<<endl; cout<<topq<<endl; for (int i=topq;i>=1;i--) printf("%d %d ",q[i][0],q[i][1]); } return 0; }