[ICPC2015 WF]Evolution in Parallel题解

题目大意:给定 1 1 1个母串和 n n n个子串,如果 x x x y y y的子序列则 x x x可以变换到 y y y,求出两个不相交的序列,分别使序列第一个子串可以沿着序列一直变换到母串。( n n n个子串都至少要出现一次,没有合法方案输出 i m p o s s i b l e impossible impossible
这道题也是寒假作业中比较简单的一道题,思路不是非常复杂。
假设有两个序列 A A A B B B,刚开始 A A A B B B中是母串。
那无非三种情况(设目前的字符串为 S S S,按长度从大到小先排序):
S S S如果能变换至 A A A的最后一个子串则 g = 1 g=1 g=1,否则 g = 0 g=0 g=0
S S S如果能变换至 B B B的最后一个子串则 h = 1 h=1 h=1,否则 h = 0 h=0 h=0
分类讨论:
1. g = 0    a n d    h = 0 1.g=0\ \ and\ \ h=0 1.g=0  and  h=0 输出 i m p o s s i b l e impossible impossible
2. g = 1    a n d    h = 1 2.g=1\ \ and\ \ h=1 2.g=1  and  h=1
再多开一个序列 C C C,代表能够塞入两个序列的子串。
如果 S S S能变换至 C C C的最后一个子串,将 S S S塞入 C C C
否则?将 S S S塞入 A A A中, C C C中所有数塞入 B B B中(因为 C C C中的子串已经违反了它的定义)
3. g = 1 3.g=1 3.g=1
S S S塞入 A A A中, C C C中所有数塞入 B B B中( C C C中子串也不一定满足定义了,直接扔掉)
4. h = 1 4.h=1 4.h=1
同理,将 3 3 3 A A A改成 B B B B B B改成 A A A
然后就可以了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 4005
using namespace std;
char cc[N][N],ch[N];
int len[N];
struct node{
	int val,id;
}a[N];
int b[N],c[N],d[N];
int i,j,k,m,n,o,p,l,s,t;
bool cmp(node a,node b) {return a.val>b.val;}
bool Cmp(int x,int y) {return a[x].val<a[y].val;}
int pd(int x,int y)
{
	x=a[x].id,y=a[y].id;
	if (len[x]>len[y]) return 0;
	for (int i=1,j=1;i<=len[y];i++)
	{
		if (cc[x][j]==cc[y][i]) j++;
		if (j>len[x]) return 1; 
	}
	return 0;
}
int main()
{
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	scanf("%d\n",&n);
	for (i=0;i<=n;i++)
	{
		scanf("%s\n",ch+1),len[i]=strlen(ch+1);
		for (j=1;j<=len[i];j++) cc[i][j]=ch[j];
		a[i]=(node){len[i],i};
	}
	sort(a+1,a+n+1,cmp);
	b[0]=1,c[0]=1;
	for (i=1;i<=n;i++)
	{
		int g=pd(i,b[b[0]]),h=pd(i,c[c[0]]);
		if (g&&h)
		{
			int f=pd(i,d[d[0]]);
			if (f) d[++d[0]]=i;
			else {
				b[++b[0]]=i;
				for (j=1;j<=d[0];j++) c[++c[0]]=d[j];
				d[0]=0;
			}
		} else if (g) {
			b[++b[0]]=i;
			for (j=1;j<=d[0];j++) c[++c[0]]=d[j];
			d[0]=0;
		}
		else if (h) {
			for (j=1;j<=d[0];j++) b[++b[0]]=d[j];
			d[0]=0;
			c[++c[0]]=i;
		}
		else {
			puts("impossible");return 0;
		}
	}
	for (i=1;i<=d[0];i++) b[++b[0]]=d[i];
	sort(b+1,b+b[0]+1,Cmp);
	sort(c+1,c+c[0]+1,Cmp);
	printf("%d %d\n",b[0]-1,c[0]-1);
	for (i=1;i<=b[0]-1;i++)
	{
		k=a[b[i]].id;
		for (j=1;j<=len[k];j++) printf("%c",cc[k][j]);
		puts("");
	}
	for (i=1;i<=c[0]-1;i++)
	{
		k=a[c[i]].id;
		for (j=1;j<=len[k];j++) printf("%c",cc[k][j]);
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值