题意:
在一个国家当中,给你一个词汇书,你可以用里面所有的字母拼凑出一个单词来,但是在这个国家当中存在一些禁用的单词,那么现在问你在不违反规则的情况下,你能尽可能的多拼凑出相应的单词来。
那么也就是说拼凑的单词当中不能够出现禁用的单词的字段。
后面看到网上教程当中的dp状态转移,傻眼了。。这都可以。
dp[i+1][cnt]=dp[i+1][cnt]+dp[i][j],我所理解的就是在i+1这个位置上面我放上cnt这个字符,将之前可行的数目累加到长度为i+1的基础上,其实我认为这个与其说是dp,倒不如说是一种递推。
而其中的ac自动机就是用来判断其中新拼凑的单词当中是否出现过类似的字串,出现了就不能够累加到相应的dp值上。
大数当然是因为方案的种类数多了之后难以用int整形存下。
代码:

1 //大数+dp+ac自动机 2 #include<iostream> 3 #include<stdlib.h> 4 #include<cstring> 5 #include<cstdio> 6 #include<queue> 7 8 const int Type=55; 9 const int Max=800; 10 const int base=100000000; 11 const int bit=30; 12 13 using namespace std; 14 15 struct node 16 { 17 node *next[Type]; 18 node *fail; 19 int id,sum; 20 }tree[Max]; 21 22 struct BigNum 23 { 24 int num[bit]; 25 int len; 26 BigNum() 27 { 28 len=1; 29 memset(num,0,sizeof(num)); 30 } 31 }dp[Type][Max]; 32 33 int MM(int a,int b) 34 { 35 return a>b?a:b; 36 } 37 38 BigNum operator+(BigNum a,BigNum b) 39 { 40 BigNum c; 41 c.len=MM(a.len,b.len); 42 int k=0,t; 43 for(int i=1;i<=c.len;i++) 44 { 45 t=a.num[i]+b.num[i]+k; 46 k=t/base; 47 c.num[i]=t%base; 48 } 49 while(k) 50 { 51 c.num[++c.len]=k%base; 52 k/=base; 53 } 54 return c; 55 } 56 57 int n,m,p,tot; 58 char s[Type],str[Type]; 59 int dx[5*Type]; 60 61 node *getroot() 62 { 63 tot=0; 64 tot++; 65 tree[tot].fail=NULL; 66 memset(tree[tot].next,NULL,sizeof(tree[tot].next)); 67 tree[tot].id=tot; 68 tree[tot].sum=0; 69 return &tree[tot]; 70 } 71 node *root; 72 73 node *getnode() 74 { 75 tot++; 76 tree[tot].fail=root; 77 memset(tree[tot].next,NULL,sizeof(tree[tot].next)); 78 tree[tot].id=tot; 79 tree[tot].sum=0; 80 return &tree[tot]; 81 } 82 83 void insert() 84 { 85 node *tmp=root; 86 int i=0; 87 while(str[i]) 88 { 89 int index=dx[str[i]+128]; 90 if(tmp->next[index]==NULL)tmp->next[index]=getnode(); 91 tmp=tmp->next[index]; 92 i++; 93 } 94 tmp->sum++; 95 } 96 97 void build_ac() 98 { 99 queue<node*> q; 100 while(!q.empty())q.pop(); 101 q.push(root); 102 while(!q.empty()) 103 { 104 node *tmp=q.front(); 105 q.pop(); 106 node *ff; 107 for(int i=0;i<n;i++) 108 if(tmp->next[i]!=NULL) 109 { 110 q.push(tmp->next[i]); 111 for(ff=tmp->fail;ff!=NULL;ff=ff->fail) 112 { 113 if(ff->next[i]!=NULL) 114 { 115 tmp->next[i]->fail=ff->next[i]; 116 if(ff->next[i]->sum==1)tmp->next[i]->sum=1; 117 break; 118 } 119 } 120 } 121 } 122 } 123 124 void solution() 125 { 126 dp[0][1].num[1]=1; 127 for(int i=0;i<m;i++) 128 { 129 for(int j=1;j<=tot;j++) 130 { 131 node *tmp=&tree[j]; 132 for(int k=0;k<n;k++) 133 { 134 if(tmp->next[k]!=NULL) 135 { 136 int index=tmp->next[k]->id; 137 if(tmp->next[k]->sum==0)dp[i+1][index]=dp[i+1][index]+dp[i][j]; 138 } 139 else 140 { 141 node *now=tmp->fail; 142 for(;now!=NULL;now=now->fail) 143 { 144 if(now->next[k]!=NULL) 145 { 146 now=now->next[k]; 147 break; 148 } 149 } 150 if(now==NULL)now=root; 151 int index=now->id; 152 if(now->sum==0)dp[i+1][index]=dp[i+1][index]+dp[i][j]; 153 } 154 } 155 } 156 } 157 } 158 void init() 159 { 160 memset(dx,-1,sizeof(dx)); 161 tot=0; 162 gets(s); 163 for(int i=0;i<n;i++) 164 { 165 if(dx[s[i]+128]==-1) 166 dx[s[i]+128]=i; 167 } 168 root=getroot(); 169 while(p--) 170 { 171 scanf("%s",str); 172 insert(); 173 } 174 } 175 void Print() 176 { 177 BigNum answer; 178 for(int i=1;i<=tot;i++) 179 answer=answer+dp[m][i]; 180 int ll=answer.len; 181 printf("%d",answer.num[ll]); 182 for(int j=ll-1;j>=1;j--) 183 { 184 if(answer.num[j]<base/10)printf("0"); 185 if(answer.num[j]<base/100)printf("0"); 186 if(answer.num[j]<base/1000)printf("0"); 187 if(answer.num[j]<base/10000)printf("0"); 188 if(answer.num[j]<base/100000)printf("0"); 189 if(answer.num[j]<base/1000000)printf("0"); 190 if(answer.num[j]<base/10000000)printf("0"); 191 printf("%d",answer.num[j]); 192 } 193 printf("\n"); 194 } 195 int main() 196 { 197 scanf("%d %d %d\n",&n,&m,&p); 198 init(); 199 build_ac(); 200 solution(); 201 Print(); 202 return 0; 203 }