POJ 1625 Censored!
题
O∧O http://poj.org/problem?id=1625
解
首先,结果很大而且没取模,所以要大数。
对不合法串建个AC自动机,注意可取的字符集的范围貌似有点奇怪,可以直接开个map存,时间反正够。
dp[i][j]表示当前长度为i,指针指在自动机的j处的数量。
对于每个长度i(0~m),每个节点j,枚举其nxt(记为k),对k的fail节点递归,如果递归中的任意一个节点end值不为0(即存在不合法串),则不更新dp[i+1][k]
否则更新dp[i+1][k]+=dp[i][j];
这组样例超棒的OVO
4 3 2 ACGT TCT C
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <map> using namespace std; typedef long long ll; struct Trie { static const int MAX_SIZE=500044; static const int CHRSET_SIZE=54; static const int HASH_SIZE=144441; int chrset_size; map<ll,ll> hash; int next[MAX_SIZE][CHRSET_SIZE],fail[MAX_SIZE],end[MAX_SIZE]; int root,L; int gethash(char key[]) { hash.clear(); int len = strlen(key); for(int i=0;i<len;i++) hash[key[i]]=i; } int newnode() { for(int i = 0;i < chrset_size;i++) next[L][i] = -1; end[L++] = 0; return L-1; } void init(char key[]) { chrset_size=strlen(key); gethash(key); L = 0; root = newnode(); } void insert(char s[]) { int len = strlen(s); int now = root; for(int i = 0;i < len;i++) { if(next[now][hash[s[i]]] == -1) next[now][hash[s[i]]] = newnode(); now=next[now][hash[s[i]]]; } end[now]++; } void build() { queue<int>Q; fail[root] = root; for(int i = 0;i < chrset_size;i++) if(next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } while(!Q.empty()) { int now = Q.front(); Q.pop(); for(int i = 0;i < chrset_size;i++) if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } int query(char buf[]) { int len = strlen(buf); int now = root; int ret = 0; for(int i = 0;i < len;i++) { now = next[now][hash[buf[i]]]; int temp = now; while(temp != root) { ret += end[temp]; end[temp] = 0; temp = fail[temp]; } } return ret; } } ac; struct BigNum { static const int MAX_LEN=25; static const int BAS=1e8; static const int LV=8; int len; ll num[MAX_LEN]; BigNum(ll rst=0) { memset(num,0,sizeof(num)); num[0]=rst%BAS; rst/=BAS; len=1; while(rst) { num[len++]=rst%BAS; rst/=BAS; } } void output(bool flag=true) { printf("%lld",num[len-1]); for(int i=len-2;i>=0;i--) printf("%08lld",num[i]); if(flag) printf("\n"); } friend BigNum operator+(BigNum x,BigNum y) { x.len=max(x.len,y.len); for(int i=0;i<x.len;i++) { x.num[i]+=y.num[i]; x.num[i+1]+=x.num[i]/BAS; x.num[i]%=BAS; } if(x.num[x.len]) x.len++; return x; } }; char key[54]; char str[54]; BigNum ans; BigNum dp[54][144]; void solve(int m) { int i,j,t,nxt,tmp,flag; dp[0][0]=BigNum(1); for(t=0;t<m;t++) for(i=0;i<ac.L;i++) for(j=0;j<ac.chrset_size;j++) { tmp=nxt=ac.next[i][j]; flag=ac.end[tmp]; while(ac.fail[tmp]!=0) { if(flag) break; tmp=ac.fail[tmp]; flag=ac.end[tmp]; } if(flag==0) dp[t+1][nxt]=dp[t+1][nxt]+dp[t][i]; } ans=BigNum(0); for(i=0;i<ac.L;i++) if(ac.end[i]==0) ans=ans+dp[m][i]; ans.output(); } int main() { int n,m,k; scanf("%d%d%d",&n,&m,&k); getchar(); gets(key); ac.init(key); for(int i = 0;i < k;i++) { gets(str); ac.insert(str); } ac.build(); solve(m); return 0; } /* 4 3 2 ACGT TCT C 4 2 3 ABCDE C BCD ABCDE */