希望自己能成为日更博主
题目连接:http://poj.org/problem?id=1625
题目大意:给你n个字母,再给你p个字符串,问有多少个长度为m的只由给出的n个字母构成的字符串,且字符串不能包括给出的p个字符串;
题解:因为这个题不用取模,所以得使用高精度,参考了博客:https://www.cnblogs.com/shangyu/p/3730815.html;这个题和HDU 2243很像,只要把他的矩阵快速幂换成高精度就可以了。dp[i+1][next] = dp[i+1][next]+dp[i][j] , dp[i][j] 表示长度为 i 在第j个结点的方案数,next为当前j点所能走到的下一个合法的结点。求不含啥啥字符串的个数时,建立ac自动机时都会有end[now]|=end[fail[now]] ,表示如果当前结点fail指向的结点被标记了,那么当前节点也要被标记。
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<queue> 5 #include<string.h> 6 using namespace std; 7 8 const int base=1e4; 9 const int DIG=4; 10 const int maxn = 11100; 11 const int MX = 1110; 12 int n,m,p; 13 int id[2200]; 14 15 struct tire{ 16 int nxt[maxn][2200],fail[maxn],end[maxn],tot,root,vis[maxn]; 17 int newNode(){ 18 for(int i=0;i<n;i++) nxt[tot][i] = -1; 19 end[tot++] = 0; 20 return tot-1; 21 } 22 void Init(){ 23 tot = 0; 24 root = newNode(); 25 } 26 void Insert(char *buf){ 27 int len = strlen(buf),i,u = root; 28 for(i=0;i<len;i++){ 29 int x = id[buf[i]]; 30 if(nxt[u][x]==-1) nxt[u][x] = newNode(); 31 u = nxt[u][x]; 32 } 33 end[u] = 1; 34 } 35 void build(){ 36 queue <int> q; 37 fail[root] = root; 38 for(int i=0;i<n;i++){ 39 if(nxt[root][i]==-1) nxt[root][i] = root; 40 else{ 41 fail[nxt[root][i]] = root; 42 q.push(nxt[root][i]); 43 } 44 } 45 while(!q.empty()){ 46 int now = q.front(); 47 q.pop(); 48 for(int i=0;i<n;i++){ 49 if(nxt[now][i]==-1) nxt[now][i] = nxt[fail[now]][i]; 50 else{ 51 fail[nxt[now][i]] = nxt[fail[now]][i]; 52 q.push(nxt[now][i]); 53 } 54 } 55 end[now]|=end[fail[now]]; 56 } 57 } 58 }ac; 59 60 struct bignum 61 { 62 int a[110],len; 63 bignum() 64 { 65 memset(a,0,sizeof(a)); 66 len=1; 67 } 68 bignum(int v) 69 { 70 memset(a,0,sizeof(a)); 71 len=0; 72 do{ 73 a[len++]=v%base; 74 v/=base; 75 }while(v); 76 } 77 bignum(const char s[]) 78 { 79 memset(a,0,sizeof(a)); 80 int k = strlen(s); 81 len = k/DIG; 82 if(k%DIG) len++; 83 int cnt = 0; 84 for(int i = k-1; i >= 0 ; i-=DIG){ 85 int t = 0; 86 int kk = i-DIG+1; 87 if(kk<0) kk =0; 88 for(int j = kk ; j <= i ; j++) 89 t = t*10+s[j]-'0'; 90 a[cnt++] = t; 91 } 92 } 93 bignum operator + (const bignum &b) const 94 { 95 bignum res; 96 res.len=max(len,b.len); 97 int i; 98 for(i=0;i<res.len;i++) 99 res.a[i]=0; 100 for(i=0;i<res.len;i++){ 101 res.a[i]+=((i<len)?a[i]:0)+((i<b.len)?b.a[i]:0); 102 res.a[i+1]+=res.a[i]/base; 103 res.a[i]=res.a[i]%base; 104 } 105 if(res.a[res.len]>0) res.len++; 106 return res; 107 } 108 void output() 109 { 110 printf("%d",a[len-1]); 111 for(int i=len-2;i>=0;i--) 112 printf("%04d",a[i]); 113 printf("\n"); 114 } 115 }dp[110][110]; 116 117 void solve() 118 { 119 for(int i=1;i<=m;i++) 120 for(int j=0;j<=ac.tot;j++) 121 dp[i][j]=bignum(0); 122 dp[0][0]=bignum(1); 123 for(int i=0;i<m;i++){ 124 for(int j=0;j<ac.tot;j++){ 125 for(int k=0;k<n;k++){ 126 if(ac.end[ac.nxt[j][k]]) continue; 127 dp[i+1][ac.nxt[j][k]]= dp[i+1][ac.nxt[j][k]]+dp[i][j]; 128 } 129 } 130 } 131 bignum ans=bignum(0); 132 for(int j=0;j<ac.tot;j++) 133 ans=ans+dp[m][j]; 134 ans.output(); 135 } 136 137 char s1[MX]; 138 139 int main() 140 { 141 scanf("%d%d%d",&n,&m,&p); 142 ac.Init(); 143 scanf("%s",s1); 144 for(int i=0;i<n;i++){ 145 id[s1[i]]=i; 146 } 147 for(int i=0;i<p;i++) 148 scanf("%s",s1),ac.Insert(s1); 149 ac.build(); 150 solve(); 151 return 0; 152 }