Codeforces Round #467 Div. 1

  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!!!!!
}

  

猜你喜欢

转载自www.cnblogs.com/Gloid/p/10439553.html