UOJ 670

题目
先考虑字符串总长度为偶数的情况,由于每个名字从前往后和从后往前都一样,那么我们相当于要找出除中间两个字符之外,两段完全一样的串。

那么这个可以看成从一个字符开始,交替扩展两个段 ,那么我们如果将一个字符的与 \(0\) 连无向边,二个字符的连两个字符间的边,这就相当于求一条从 \(0\) 出发的欧拉回路,可以发现我们在回路上交替选边最终一定能生成合法方案。而对于不与 \(0\) 联通的边,可以发现一种边要么出现次数全部为偶数,要么存在一个自环为奇数 (放在字符串中间)且剩下的都为偶数。

字符串为奇数长度的也类似,就是把 \(0\) 联通块外的边两两放在字符串两侧,从 \(0\) 开始跑一边欧拉回路并将其放在字符串中间位置。

这道题保证有解就很良心,无解的情况感觉太多了。

\(\text{Warning:}\) 跑欧拉回路的时候不能忘了当前弧优化,要不然会被卡 T 。

const int N=1e6+5;
int n,m,s[N],b[N][3],f[N],summ;
struct node{
	int next,to,id,flag,rev;
}a[N*2];int head[N],cnt=1,d[N];
int vis[N*2],top,tota,totb,tg[N];
map<pii,int>ma;
pii st[N*2],x[N],y[N];
struct Qu{
	int x,y,id,rev;
}t[N];int tou;
int cmp(Qu x,Qu y){
	if(x.x!=y.x)return x.x<y.x;
	else return x.y<y.y;
}
void add(int e,int r,int t,int w){
	a[++cnt].next=head[e];
	a[cnt].to=r;
	a[cnt].id=t;
	a[cnt].rev=w;
	head[e]=cnt;
}
void dfs(int u){
	vis[u]=1;
	for(int i=head[u];i;i=head[u]){
		head[u]=a[i].next;
		if(a[i].flag)continue;
		a[i].flag=a[i^1].flag=1;
		dfs(a[i].to);
		st[++top]=mp(a[i].id,a[i].rev);
	}
}
void solve1(){
	dfs(0);
	for(int i=1;i<=n;i++){
		if(vis[b[i][1]] || vis[b[i][2]])continue;
		if(b[i][2]<b[i][1])swap(b[i][2],b[i][1]),tg[i]=1;
		t[++tou]={b[i][1],b[i][2],i,tg[i]};
		ma[mp(b[i][1],b[i][2])]++;
	}
	sort(t+1,t+tou+1,cmp);
	int flag=0;
	for(int i=1;i<=n;i++){
		if(ma[mp(b[i][1],b[i][2])]%2==1)flag=b[i][1];
	}
	int tmp=0;
	while(top){
		if(!tmp)x[++tota]=mp(st[top].fi,st[top].se);
		else y[++totb]=mp(st[top].fi,st[top].se);
		tmp^=1;top--;
	}
	if(!flag){
		for(int i=1;i<=tou;i++){
			if(ma[mp(t[i].x,t[i].y)]%2==0)x[++tota]=mp(t[i].id,t[i].rev);
			else y[++totb]=mp(t[i].id,t[i].rev);
			ma[mp(t[i].x,t[i].y)]--;
		}
	}
	else{
		for(int i=1;i<=tou;i++){
			if(t[i].x==flag && t[i].y==flag)continue;
			if(ma[mp(t[i].x,t[i].y)]%2==0)x[++tota]=mp(t[i].id,t[i].rev);
			else y[++totb]=mp(t[i].id,t[i].rev);
			ma[mp(t[i].x,t[i].y)]--;
		}
		for(int i=1;i<=n;i++){
			if(b[i][1]!=flag || b[i][2]!=flag)continue;
			x[++tota]=mp(i,0);
		}
	}
}
void solve2(){
	dfs(0);
	for(int i=1;i<=n;i++){
		if(vis[b[i][1]] || vis[b[i][2]])continue;
		if(b[i][2]<b[i][1])swap(b[i][2],b[i][1]),tg[i]=1;
		t[++tou]={b[i][1],b[i][2],i,tg[i]};
		ma[mp(b[i][1],b[i][2])]++;
	}
	sort(t+1,t+tou+1,cmp);
	for(int i=1;i<=tou;i++){
		if(ma[mp(t[i].x,t[i].y)]%2==0)x[++tota]=mp(t[i].id,t[i].rev);
		else y[++totb]=mp(t[i].id,t[i].rev);
		ma[mp(t[i].x,t[i].y)]--;
	}
	int tmp=0;
	while(top){
		if(!tmp)x[++tota]=mp(st[top].fi,st[top].se);
		else y[++totb]=mp(st[top].fi,st[top].se);
		tmp^=1;top--;
	}
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++){
		s[i]=read();
		summ=summ+s[i];
		for(int k=1;k<=s[i];k++){
			b[i][k]=read();
		}
	}
	for(int i=1;i<=n;i++){
		add(b[i][1],b[i][2],i,0);
		add(b[i][2],b[i][1],i,1);
	}
	if(summ%2==0){
		solve1();
	}
	else{
		solve2();
	}
	for(int i=1;i<=tota;i++){
		print(x[i].fi);
	}
	for(int i=totb;i>=1;i--){
		print(y[i].fi);
	}
	Flush();
	cout<<'\n';
	for(int i=1;i<=tota;i++){
		print(x[i].se);
	}
	for(int i=totb;i>=1;i--){
		print(y[i].se^1);
	}
	Flush();
	return 0;
}
posted @ 2021-10-07 11:41  newbiewzs  阅读(107)  评论(0)    收藏  举报