[JSOI2009]密码

Description

Input

Output

Sample Input
10 2
hello
world

Sample Output
2
helloworld
worldhello

HINT


一看\(n\)这么小就要状压……我们设\(f[i][j][s]\)表示长度为\(i\),AC自动机上节点为\(j\),出现的字符串的状态为\(s\)的方案数,然后直接枚举转移即可

然后难点就在于如何输出方案

首先42这数字非常妙(生命、宇宙以及任何事情的终极答案)

如果存在一个字符可以任意选的情况,那么答案至少也要为2*26=52,所以这种情况是不存在的

所以就直接爆搜,\(O(n!)\)搜索,然后中间疯狂剪枝就好

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
	int x=0,f=1;char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)	putchar('-'),x=-x;
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
const int N=1e2;
struct S1{
	int trie[N+10][26],fail[N+10],End[N+10];
	int root,tot;
	void insert(char *s,int ID){
		int len=strlen(s),p=root;
		for (int i=0;i<len;i++){
			if (!trie[p][s[i]-'a'])	trie[p][s[i]-'a']=++tot;
			p=trie[p][s[i]-'a'];
		}
		End[p]=1<<ID;
	}
	void make_fail(){
		static int h[N+10];
		int head=1,tail=0;
		for (int i=0;i<26;i++)	if (trie[root][i])	h[++tail]=trie[root][i];
		for (;head<=tail;head++){
			int Now=h[head];
			End[Now]|=End[fail[Now]];
			for (int i=0;i<26;i++){
				if (trie[Now][i]){
					int son=trie[Now][i];
					fail[son]=trie[fail[Now]][i];
					h[++tail]=son;
				}else	trie[Now][i]=trie[fail[Now]][i];
			}
		}
	}
}AC;//Aho-Corasick automaton
int work(char *s,char *t){
	int lens=strlen(s),lent=strlen(t),Ans=0;
	for (int i=0;i<lens;i++){
		int res=0,x=i,y=0;
		while (x<lens&&y<lent){
			if (s[x]!=t[y])	break;
			res++,x++,y++;
		}
		if (x!=lens)	continue;
		Ans=max(Ans,res);
	}
	return Ans;
}
ll f[30][N+10][(1<<10)+10];
int pos[15],Len[15],g[15][15],L,n,cnt;
bool vis[15];
char s[15][15];
struct S2{char s[N+10];}A[50];
bool operator <(const S2 &x,const S2 &y){
	int lenx=strlen(x.s),leny=strlen(y.s);
	if (lenx!=leny)	return lenx<leny;
	for (int i=0;i<lenx;i++)	if (x.s[i]!=y.s[i])	return x.s[i]<y.s[i];
	return 0;
}
void dfs(int x,int len){
	if (len>L)	return;
	if (x==n){
		static char T[N+10];
		for (int i=0;i<Len[pos[0]];i++)	T[i]=s[pos[0]][i];
		int L=Len[pos[0]];
		for (int i=1;i<n;i++){
			for (int j=0;j<Len[pos[i]];j++)
				T[j+L-g[pos[i-1]][pos[i]]]=s[pos[i]][j];
			L+=Len[pos[i]]-g[pos[i-1]][pos[i]];
		}
		memcpy(A[cnt++].s,T,sizeof(T));
		return;
	}
	for (int i=0,tmp;i<n;i++){
		if (!vis[i]){
			pos[x]=i,vis[i]=1;
			tmp=len+Len[i]-(x?g[pos[x-1]][i]:0);
			dfs(x+1,tmp);
			pos[x]=0,vis[i]=0;
		}
	}
}
int main(){
	L=read(),n=read();
	for (int i=0;i<n;i++){
		scanf("%s",s[i]);
		Len[i]=strlen(s[i]);
		AC.insert(s[i],i);
	}
	AC.make_fail();
	f[0][0][0]=1;
	for (int i=0;i<L;i++){
		for (int j=0;j<=AC.tot;j++){
			for (int s=0;s<1<<n;s++){
				if (!f[i][j][s])	continue;
				for (int k=0;k<26;k++){
					int son=AC.trie[j][k];
					f[i+1][son][s|AC.End[son]]+=f[i][j][s];
				}
			}
		}
	}
	ll Ans=0;
	for (int i=0;i<=AC.tot;i++)	Ans+=f[L][i][(1<<n)-1];
	printf("%lld\n",Ans);
	if (Ans>42)	return 0;
	for (int i=0;i<n;i++)
		for (int j=0;j<n;j++)
			g[i][j]=work(s[i],s[j]);
	dfs(0,0);
	sort(A,A+cnt);
	for (int i=0;i<cnt;i++)	printf("%s\n",A[i].s);
	return 0;
}
posted @ 2019-03-06 21:49  Wolfycz  阅读(269)  评论(0编辑  收藏  举报