POJ1625----AC自动机+大数+DP
发布时间:2020-12-14 04:08:46 所属栏目:大数据 来源:网络整理
导读:题目地址:http://poj.org/problem?id=1625 题目意思: 给你一个字典,里面有n个不同的字符 然后给你p个不允许出现的字符串 要你求出在由字典里的字符组成的一个m长度的字符串不含禁止字符串的种数有多少 解题思路: 假设在一个AC自动机上,状态j的长度已经
题目地址:http://poj.org/problem?id=1625 题目意思: 给你一个字典,里面有n个不同的字符 然后给你p个不允许出现的字符串 要你求出在由字典里的字符组成的一个m长度的字符串不含禁止字符串的种数有多少 解题思路: 假设在一个AC自动机上,状态j的长度已经有i了,用dp[i][j]表示 那么dp[i+1][tmp] += dp[i][j] ?其中tmp这个节点可以由j合法的转移(合法就是不会出现禁止的情况) 再就是本题的数据规模很大,50^50,所以要用大数 再就是要注意几个细节 比如最后大数的结果为0的话 或者是当上面说的j已经是非法点了,那么就不能跳转了 再就是本题输入的char可能会有到255,那么会出现负数,所以我用了hash的方法来重定向下标 下面上代码: #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int maxnode = 120; const int size=256; int hash[size]; int wordn,m,p; struct AC { int ch[maxnode][size]; int f[maxnode]; bool val[maxnode]; int sz; void init() { sz=1; memset(ch[0],-1,sizeof(ch[0])); val[0]=false; } void insert(char *s) { int len = strlen(s); int u=0; for(int i=0;i<len;i++) { int c=hash[s[i]+128]; if(-1 == ch[u][c]) { memset(ch[sz],sizeof(ch[sz])); val[sz]=false; ch[u][c] = sz++; } u=ch[u][c]; } val[u] = true; } void getfail() { queue<int> q; for(int i=0;i<wordn;i++) { int u = ch[0][i]; if(-1!=u) { f[u]=0; q.push(u); } else ch[0][i]=0; } while(!q.empty()) { int r=q.front(); q.pop(); //printf("qn"); val[r] |= val[f[r]]; for(int i=0;i<wordn;i++) { int &v=ch[r][i]; if(-1!=v) { q.push(v); f[v]=ch[f[r]][i]; } else { v=ch[f[r]][i]; } } } } }ac; struct bignumber { int a[100]; void init() { memset(a,sizeof(a)); } void print() { int j=99; while(a[j]==0) j--; if(j<0) { printf("0n"); return ; } while(j>=0) { printf("%d",a[j]); j--; } printf("n"); } }; void add(bignumber &x,bignumber y) { for(int i=0;i<99;i++) { x.a[i]+=y.a[i]; x.a[i+1]+=x.a[i]/10; x.a[i]=x.a[i]%10; } } bignumber dp[55][120]; void dp_ac() { memset(dp,sizeof(dp)); dp[0][0].a[0]=1; for(int i=0;i<m;i++) { for(int j=0;j<ac.sz;j++) { if(ac.val[j]) continue; for(int k=0;k<wordn;k++) { int tmp = ac.ch[j][k]; if(!ac.val[tmp] && !ac.val[j]) { add(dp[i+1][tmp],dp[i][j]); } } } } bignumber ans; ans.init(); for(int i=0;i<ac.sz;i++) { add(ans,dp[m][i]); } ans.print(); } int main() { while(~scanf("%d%d%d",&wordn,&m,&p)) { ac.init(); char str[100]; getchar(); gets(str); memset(hash,sizeof(hash)); for(int i=0;i<wordn;i++) { hash[str[i]+128]=i; } for(int i=0;i<p;i++) { gets(str); ac.insert(str); } ac.getfail(); dp_ac(); } return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |