BZOJ 1030 AC自动机+DP
询问由26个字母组成的长度为n的字符串中含有给定一些字符串为子串的种数。
考虑补集。我们求出不含有给定字符串为子串的种数。
这个问题可以由AC自动机上DP求得。
对给定的串建立AC自动机。我们令dp[i][j]表示字符串第i位走到AC自动机上j节点的方法数。那么对应于一个字符串,就相当于AC自动机走到了某个节点的位置。
现在由于不能包含某些字符串为子串,那么这个子串的end节点一定不能走,fail指针指向这些子串的end节点的节点也不能走。
剩下的就可以进行DP了。那么dp[i][ch[j][k]]+=dp[i-1][j].
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-4 # define MOD 10007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=6010; //Code begin... int trie[N][27], top, fail[N], dp[105][N]; void init(){top=1; mem(trie[0],0);} void ins(char *s){ int rt, nxt; for (rt=0; *s; rt=nxt, ++s){ nxt=trie[rt][*s-'A']; if (!nxt) mem(trie[top],0), trie[rt][*s-'A']=nxt=top++; } trie[rt][26]=1; } void makefail(){ int u, v, bg, ed; static int q[N]; fail[0]=bg=ed=0; FO(i,0,26) if ((v=trie[0][i])) fail[q[ed++]=v]=0; while (bg<ed){ u=q[bg++]; FO(i,0,26) { if ((v=trie[u][i])) fail[q[ed++]=v]=trie[fail[u]][i]; else trie[u][i]=trie[fail[u]][i]; } trie[u][26]|=trie[fail[u]][26]; } } int work(int m){ int ans1=1, ans2=0; FOR(i,1,m) ans1=ans1*26%MOD; dp[0][0]=1; FOR(i,1,m) FO(j,0,top) { if (trie[j][26]) continue; FO(k,0,26) dp[i][trie[j][k]]=(dp[i][trie[j][k]]+dp[i-1][j])%MOD; } FO(i,0,top) if (!trie[i][26]) ans2=(ans2+dp[m][i])%MOD; return ((ans1-ans2)%MOD+MOD)%MOD; } char str[105]; int main () { int n, m; scanf("%d%d",&n,&m); init(); FOR(i,1,n) scanf("%s",str), ins(str); makefail(); printf("%d\n",work(m)); return 0; }