【JZOJ3472】匹配

【JZOJ3472】匹配

by AmanoKumiko

Description

给定k个字符串以及长度为n的母串可选字母的集合,问母串要完整出现给定的k个字符串的方案数,答案模1000000007,字符仅包含小写字母。

Input

第一行两个整数n、k,表示字符串的长度和给定字符串的个数。

接下来k行每行一个字符串。

接下来一行1个整数m表示可选字母集合内元素个数。

接下来一行给出一个长为m的字符串,表示字母的集合(可能有重复)。

Output

一个整数ans,表示方案数。

Sample Input

3 2
cr
rh
4
acrh

Sample Output

1
【样例解释】
只有crh符合。
 

Data Constraint

30%的数据n<=10,m<=3。

60%的数据n<=40。

另有10%的数据k=0。

另有10%的数据m=1。

100%的数据n<=100,m<=10,k<=8,给定字符串长度<=30。

Solution

AC自动机上dp套路题

1.对k个串建AC自动机

2.统计每个点可以匹配串的集合(状压)

3.预处理每个点加上一个字符后会去到的点

4.设\(f[i][j][S]\)表示放了\(i\)个字符,到了AC自动机上第\(j\)个点,已匹配的字符串集合为\(S\)的方案数,转移显然

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define Fs(i,a) for(int i=last[a];i;i=e[i].next)
#define LL long long
#define mo 1000000007
#define P 250
#define N 110
#define K 15
#define L 30

int n,m,k,cnt,len[K],top,last[P],f[N][P][1<<8],ans;
struct node{int en,next;}e[P*2];
void add(int a,int b){e[++cnt]=(node){b,last[a]};last[a]=cnt;}
char s[K][L],ch[K],c[K];
bool vis[26];
queue<int>q;
struct ACM{
	int son[P][26],pos[P][26],fail[P],tmp[P],p;
	void insert(int x){
		int u=1;
		F(j,1,len[x])!son[u][s[x][j]-'a']?u=son[u][s[x][j]-'a']=++p:u=son[u][s[x][j]-'a'];
		tmp[u]|=1<<x-1;
	}
	void build(){
		F(i,0,25)son[0][i]=1;q.push(1);
		while(!q.empty()){
			int u=q.front();q.pop();add(fail[u],u);
			F(i,0,25){
				int v=son[u][i],Fail=fail[u];
				if(!v){son[u][i]=son[Fail][i];continue;}
				add(u,v);fail[v]=son[Fail][i];q.push(v);
			}
		}
	}
	void calc(){
		F(i,1,p){
			Fs(j,i)tmp[e[j].en]|=tmp[i];//匹配串的集合
			F(j,0,25){int v=i;while(v&&!son[v][j])v=fail[v];pos[i][j]=max(son[v][j],1);}//加上一个字符后会去到的点
		}
	}	
}t;

int main(){
	t.p=1;
	scanf("%d%d",&n,&k);
	F(i,1,k)scanf("%s",s[i]+1),len[i]=strlen(s[i]+1),t.insert(i);
	t.build();t.calc();
	scanf("%d%s",&m,ch+1);
	F(i,1,m)if(!vis[ch[i]-'a'])c[++top]=ch[i],vis[ch[i]-'a']=1;
	f[0][1][0]=1;
	F(i,0,n-1) F(j,1,t.p) F(S,0,(1<<k)-1)if(f[i][j][S]){
		F(x,1,m){int y=t.pos[j][c[x]-'a'];if(y)(f[i+1][y][S|t.tmp[y]]+=f[i][j][S])%=mo;}
	}
	F(i,1,t.p)(ans+=f[n][i][(1<<k)-1])%=mo;//状压DP
	printf("%d",ans);
	return 0;
}
posted @ 2021-02-03 19:37  冰雾  阅读(93)  评论(0编辑  收藏  举报