「ZOJ1642」匹配 - AC自动机+动态规划+状态压缩 | Bill Yang's Blog

「ZOJ1642」匹配 - AC自动机+动态规划+状态压缩

题目大意

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


题目分析

发现题目中$k$极小,因此可以对$k$进行状态压缩。

先将所有串建成AC自动机。

设$f[i,j,s]$表示当前长度为$i$,运行到了自动机上的$j$号结点,所包含的字符串状态为$s$。

在AC自动机上扩展trie图,下传危险标记,使得动规更加容易。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=305;
struct Tree {
int child[26],fail,next,danger;
};
struct Aho_Corasick_Automaton {
int root,cnt;
Tree tree[maxn];
#define ch(x,i) tree[x].child[i]
#define fail(x) tree[x].fail
Aho_Corasick_Automaton() {
init();
}
void init() {
root=cnt=1;
memset(tree,0,sizeof(tree));
}
int insert(string s,int id) {
int now=root;
for(int i=0; i<s.length(); i++) {
int j=s[i]-'a';
if(!ch(now,j))ch(now,j)=++cnt;
now=ch(now,j);
}
tree[now].danger=1<<(id-1);
return now;
}
void buildfail() {
queue<int>Q;
Q.push(root);
while(!Q.empty()) {
int now=Q.front();
Q.pop();
for(int i=0; i<26; i++) {
int& next=ch(now,i);
if(!next) { //补全trie图
next=ch(fail(now),i)?ch(fail(now),i):root;
continue;
}
Q.push(next);
int p=fail(now);
if(p)fail(next)=ch(p,i);
else fail(next)=root;
tree[next].next=tree[fail(next)].danger?fail(next):tree[fail(next)].next;
tree[next].danger|=tree[tree[next].next].danger;
}
}
}
} ac;
const LL mod=1000000007;
int n,k,m;
string s;
LL f[105][305][1<<8];
int main() {
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1; i<=k; i++) {
string s;
cin>>s;
ac.insert(s,i);
}
ac.buildfail();
cin>>m>>s;
sort(s.begin(),s.end());
auto it=unique(s.begin(),s.end());
s.erase(it,s.end());
f[0][1][0]=1;
for(int i=0; i<n; i++)
for(int j=1; j<=ac.cnt; j++)
for(int S=0; S<(1<<k); S++)
for(int x=0; x<s.length(); x++) {
int Next=ac.tree[j].child[s[x]-'a'];
int NextS=S|ac.tree[Next].danger;
f[i+1][Next][NextS]=(f[i+1][Next][NextS]+f[i][j][S])%mod;
}
LL ans=0;
for(int i=1; i<=ac.cnt; i++)ans=(ans+f[n][i][(1<<k)-1])%mod;
printf("%lld\n",ans);
return 0;
}
本篇文章有用吗?有用还不快点击!
0%