IOI2021集训队作业154BE Evolution in Parallel

\(n+1\)个字符串。如果\(s_i\)\(s_j\)的子序列,则连边\((j,i)\)

现在要求找到两条路径,使得它们只在\(0\)处相交,并且覆盖所有点。

\(n\le 4000\)


哇哈为什么我想到了dilworth引理……

先按照长度排序,然后维护两条链的链尾,设为\(a,b\)

如果\((i,a)\in E\)\((i,b)\in E\)只满足一个,则直接接在后面。

如果都不满足则无解。

如果都满足,则搞一个\(c=i\),暂时把两条链合成一条链。后面接着做,如果能接在这条链后面则接;如果不能接,就把它丢到\(a\)\(b\)后面,然后\(c\)接在另一条的后面,于是又分开为两条链。(在这个局面之后链尾分别为\(i\)\(i-1\),并且没有其它方法使得构造后链尾不为\(i\)\(i-1\),相当于把问题划分成前后两部分。)


using namespace std;
#include <bits/stdc++.h>
#define N 4005
void imp(){
	printf("impossible\n");
	exit(0);
}
int n;
char str[N][N];
int s[N][N],t[N][N][3];
int len[N];
int q[N];
bool cmpq(int x,int y){return len[x]<len[y];}
void init(int i,char str[]){
	int m=len[i]=strlen(str+1);
	t[i][m+1][0]=t[i][m+1][1]=t[i][m+1][2]=m+1;
	for (int j=m;j>=1;--j){
		s[i][j]=(str[j]=='A'?0:str[j]=='C'?1:2);
		memcpy(t[i][j],t[i][j+1],sizeof t[i][j]);
		t[i][j][s[i][j+1]]=j+1;
	}
	memcpy(t[i][0],t[i][1],sizeof t[i][0]);
	t[i][0][s[i][1]]=1;
}
bool sub(int u,int v){
	int x=0;
	for (int i=1;i<=len[u];++i){
		x=t[v][x][s[u][i]];
		if (x>len[v])
			return 0;
	}
	return 1;
}
int f[N];
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d",&n);
	scanf("%s",str[n+1]+1),len[n+1]=strlen(str[n+1]+1);
	for (int i=1;i<=n;++i)	
		scanf("%s",str[i]+1),len[i]=strlen(str[i]+1);
	for (int i=1;i<=n;++i)	
		q[i]=i;
	sort(q+1,q+n+1,cmpq);
	init(n+1,str[n+1]);
	for (int i=1;i<=n;++i)
		init(i,str[q[i]]);
	if (!sub(n,n+1))
		imp();
	f[n]=n+1;
	int a=n,b=n+1,c=0;
	for (int i=n-1;i>=1;--i){
		if (c){
			if (sub(i,i+1))
				f[i]=i+1;
			else{
				if (sub(i,a))
					f[i]=a,f[c]=b;
				else if (sub(i,b))
					f[i]=b,f[c]=a;
				else
					imp();
				a=i+1,b=i;
				c=0;
			}
		}
		else{
			if (sub(i,a)){
				if (sub(i,b))
					c=i;
				else
					f[i]=a,a=i;
			}
			else if (sub(i,b))
				f[i]=b,b=i;
			else
				imp();
		}
	}
	if (c)
		f[c]=a;
	static bool bz[N];
	int cnt0=0;
	for (int x=1;x<=n;x=f[x])
		bz[x]=1,cnt0++;
	printf("%d %d\n",cnt0,n-cnt0);
	for (int i=1;i<=n;++i)
		if (bz[i])
			printf("%s\n",str[q[i]]+1);
	for (int i=1;i<=n;++i)
		if (!bz[i])
			printf("%s\n",str[q[i]]+1);
	return 0;
}
posted @ 2021-03-02 20:50  jz_597  阅读(90)  评论(0编辑  收藏  举报