思路:
AC自动机+DP+高精度
细节错误:
(1):大数加法写错
(2):滚动数组更新写错
注意:
(1):若用矩阵乘法复杂度为O(snode^3*log(M)); TLE
(2):若用矩阵乘法的复杂度为O(snode*M*N); AC
PS.函数传参时传引用会比传变量快
源代码:
/*AC代码:766ms*/ #include <iostream> #include <cstdio> #include <memory.h> #include <algorithm> #define INF 1e8 #define kind 50 #define MAXN 1005 #define max(a,b) (a>b?a:b) using namespace std; struct Node { int next[kind],v,fail; }Trie[20000]; int snode;//字典树的总结点数(总状态数) int N,M,P; int Q[10000],head,tail; int hash[300]; int map[105][105]; char word[15];//模式串 struct Array { int num[100],len; void Init() { len=0; memset(num,0,sizeof(num)); } }dp[2][105],ans,res; /*------------------------AC自动机模版---------------------*/ void set_node(int x) { memset(Trie[x].next,0,sizeof(Trie[x].next)); Trie[x].v=0;//表示是否是危险结点 Trie[x].fail=-1; } void Insert(char s[]) { int i=0,pos=0,index; while(s[i]) { index=hash[s[i]]; if(Trie[pos].next[index]==0) { set_node(++snode); Trie[pos].next[index]=snode; } if(Trie[pos].v)/*危险结点为其子结点不必继续(剪枝)*/ break; pos=Trie[pos].next[index]; i++; } Trie[pos].v++; } void Find_Fail(int pre,int ith,int now) { if(!pre)//如果他的父节点是root,fail直接指向root { Trie[now].fail=0; return; } int temp=Trie[pre].fail; while(temp!=-1) { if(Trie[temp].next[ith]!=0) { Trie[now].fail=Trie[temp].next[ith]; if(Trie[Trie[temp].next[ith]].v)//注意 Trie[now].v++; return; } temp=Trie[temp].fail; } if(temp==-1) Trie[now].fail=0; return; } void Build_AC_Fail() { int i,pos; head=tail=0; Trie[0].fail=-1; Q[head++]=0; while(head!=tail) { pos=Q[tail++]; for(i=0;i<N;i++) { if(Trie[pos].next[i]!=0)//存在就要去找fail指针 { Find_Fail(pos,i,Trie[pos].next[i]); Q[head++]=Trie[pos].next[i]; } else//让它的next指向pos的fail的next Trie[pos].next[i]=Trie[Trie[pos].fail].next[i]; } } } /*------------------------AC自动机模版---------------------*/ void Init() { int i; char s[60]; set_node(0);snode=0; scanf("%s",s); for(i=0;i<N;i++) hash[s[i]]=i; for(i=1;i<=P;i++) { scanf("%s",word); Insert(word); } /* for(i=0;i<N;i++) printf("%d ",hash[s[i]]); printf("\n"); */ } /* void get_map() { int i,j,u; memset(map,0,sizeof(map)); for(i=0;i<=snode;i++) { if(Trie[i].v) continue; for(j=0;j<N;j++) { u=Trie[i].next[j]; if(Trie[u].v) continue; map[i][u]++; } } for(i=0;i<=snode;i++) { for(j=0;j<=snode;j++) printf("%d ",map[i][j]); printf("\n"); } } */ void Print(Array a) { int i,len=a.len; for(i=len-1;i>=0;i--) printf("%d",a.num[i]); printf("\n"); } void Add(Array &a,Array &b) { int i,l; //if(a.len==0) a.len=1; //if(b.len==0) b.len=1; res.Init(); l=max(a.len,b.len); //printf("*%d %d %d\n",a.len,b.len,l); res.len=l; for(i=0;i<l;i++) { res.num[i]+=(a.num[i]+b.num[i]);//注意+= res.num[i+1]+=res.num[i]/10; res.num[i]%=10; } if(res.num[l]!=0) res.len++; //Print(res); } void Solve() { int i,j,k,temp; Build_AC_Fail(); for(i=0;i<2;i++) { for(j=0;j<=snode;j++) dp[i][j].Init(); } //get_map(); dp[0][0].len=1; dp[0][0].num[0]=1; int id=0; for(i=0;i<=M-1;i++) { for(j=0;j<=snode;j++) { if(Trie[j].v) continue; if(dp[id][j].len==0) continue; for(k=0;k<N;k++) { temp=Trie[j].next[k];//化简 if(!Trie[temp].v) { //printf("-----\n"); //Print(dp[id][j]); //Print(dp[id^1][temp]); Add(dp[id^1][temp],dp[id][j]); dp[id^1][temp]=res; //Print(dp[id^1][temp]); } } } //注意滚动更新 for(j=0;j<=snode;j++) dp[id][j].Init(); id^=1; } ans.Init(); ans.len=1; ans.num[0]=0; for(i=0;i<=snode;i++) { if(Trie[i].v) continue; Add(ans,dp[id][i]); ans=res; //Print(dp[id][i]); } Print(ans); } int main() { scanf("%d%d%d",&N,&M,&P); Init(); Solve(); return 0; }