POJ 1625 Censored!(自动机DP+高精度)

题意:给出包含n个字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。

数据范围:1<=n,m<=50,0<=p<=10

思路:设不同的后缀为不同的状态,可以由自动机建立状态转移图DFA,确定状态转移矩阵即可

由于本题没对结果取模,所以是高精度,所以m的范围很小50,不需要矩阵二分幂,否则会更麻烦,,所以最多连成50次矩阵,复杂度O(n^2*m )

//Accepted780K469MSC++5474B#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<map>using namespace std;/************************高精度模版*************************************//* * 高精度,支持乘法和加法 */struct BigInt{const static int mod = 10000;const static int DLEN = 4;int a[600],len;BigInt(){memset(a,0,sizeof(a));len = 1;}BigInt(int v){memset(a,0,sizeof(a));len = 0;do{a[len++] = v%mod;v /= mod;}while(v);}BigInt(const char s[]){memset(a,0,sizeof(a));int L = strlen(s);len = L/DLEN;if(L%DLEN)len++;int index = 0;for(int i = L-1;i >= 0;i -= DLEN){int t = 0;int k = i – DLEN + 1;if(k < 0)k = 0;for(int j = k;j <= i;j++)t = t*10 + s[j] – '0';a[index++] = t;}}BigInt operator +(const BigInt &b)const{BigInt res;res.len = max(len,b.len);for(int i = 0;i <= res.len;i++)res.a[i] = 0;for(int i = 0;i < res.len;i++){res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);res.a[i+1] += res.a[i]/mod;res.a[i] %= mod;}if(res.a[res.len] > 0)res.len++;return res;}BigInt operator *(const BigInt &b)const{BigInt res;for(int i = 0; i < len;i++){int up = 0;for(int j = 0;j < b.len;j++){int temp = a[i]*b.a[j] + res.a[i+j] + up;res.a[i+j] = temp%mod;up = temp/mod;}if(up != 0)res.a[i + b.len] = up;}res.len = len + b.len;while(res.a[res.len – 1] == 0 &&res.len > 1)res.len–;return res;}void output(){printf("%d",a[len-1]);for(int i = len-2;i >=0 ;i–)printf("%04d",a[i]);printf("\n");}};/***************************************************************************/struct mat{int a[105][105];int n;mat(int sz){for(int i=0;i<sz;i++)for(int j=0;j<sz;j++)a[i][j]=0;n=sz;}mat(){}};mat DFA; //dfa状态转移图int n,m,p;char str[55];map<char,int> alp; //全部字母表struct node{node *fail;node *son[50];bool flag;int id; //状态序号}trie[105],*root,*que[105];struct AC{int head,tail,sz;node *createnode(){trie[sz].fail=NULL;memset(trie[sz].son,0,sizeof(trie[sz].son));trie[sz].id=sz;trie[sz].flag=0;return &trie[sz++];}void ini(){head=tail=sz=0;root=createnode();}void Insert(char str[]){node *cur=root;for(int i=0;str[i];i++){int val = alp[str[i]];if(cur->son[val]==NULL)cur->son[val]=createnode();cur=cur->son[val];}cur->flag=true;}void acfun(){que[head++]=root;while(tail<head){node *cur=que[tail++];for(int i=0;i<n;i++){if(cur->son[i]!=NULL){if(cur==root) cur->son[i]->fail=root;else cur->son[i]->fail=cur->fail->son[i];if(cur->son[i]->fail->flag) cur->son[i]->flag=true;que[head++]=cur->son[i];}elseif(cur==root) cur->son[i]=root;else cur->son[i]=cur->fail->son[i];}}}mat DFAfun(){mat ans=mat(sz);for(int i=0;i<sz;i++)if(!trie[i].flag)for(int j=0;j<n;j++)if(!trie[i].son[j]->flag)ans.a[i][trie[i].son[j]->id]++;return ans;}}ac;void print(mat m) //debug{for(int i=0;i<m.n;i++,puts(""))for(int j=0;j<m.n;j++)printf("%3d",m.a[i][j]);}BigInt dp[2][101];void ini(){alp.clear();ac.ini();for(int i=0;i<DFA.n;i++) dp[0][i]=0;dp[0][0]=1;}int main(){while(~scanf("%d%d%d",&n,&m,&p)){ini();gets(str); //吃掉剩下的换行gets(str);for(int i=0;str[i];i++){alp[str[i]] = i;}ac.ini();for(int i=0;i<p;i++){gets(str);ac.Insert(str);}ac.acfun();DFA=ac.DFAfun();// print(DFA);for(int i=1;i<=m;i++){for(int j=0;j<DFA.n;j++) //别忘了每次循环要初始化dp[i&1][j]=0;for(int j=0;j<DFA.n;j++)for(int k=0;k<DFA.n;k++)if(DFA.a[j][k])dp[i&1][k]=dp[i&1][k]+dp[(i&1)^1][j]*DFA.a[j][k];}BigInt ans;for(int i=0;i<DFA.n;i++){ans=ans+dp[m&1][i];}ans.output();}return 0;}

有的事情现在不做,就一辈子也不会做了。

POJ 1625 Censored!(自动机DP+高精度)

相关文章:

你感兴趣的文章:

标签云: