又是一个Trie图上找递推关系的题~只不过这次是单字符串做一个Trie图(这样的话用扩展kmp也可以8
把样例研究一下再结合Trie图基本就能确定出等式关系了,设dp[i]为
现在在Trie图上的节点i,还需要走多少步(期望意义下)才能凑出给定的字符串
容易知道当走到尽头的时候dp[n]=0;其他的项地推关系可以表示为dp[u]=1+\sum i/n*dp[v] ,其中v是u走向的下一个节点。
以样例n=2,s=”ABA”为例,Tried图和方程组如下
解这个方程组可得dp[0]=5,就是我们要的结果了。
具体代码实现的时候,直接对每个结点都把转移记录下来,然后用高斯消元解方程即可。注意应该把n乘到等式左边,然后用整数的高斯消元,不然会有误差wa。
#include<bits/stdc++.h> #define eps 1e-15 using namespace std; const int maxn=200+15; const int INF=0x3f3f3f3f; const int mod=1e9+7; const int maxnode=500; typedef long long LL; typedef unsigned long long ULL; long double A[maxn][maxn],X[maxn]; int equ,var; void Gauess(int n){ for(int i = 0; i < n; ++i){ int r = i; while(r < n && !A[r][i]) ++r; if(r != i) for(int j = 0; j <= n; ++j) swap(A[r][j], A[i][j]); for(int k = i+1; k < n; ++k) if(A[k][i]){ LL f = A[k][i]; for(int j = i; j <= n; ++j) A[k][j] = A[k][j] * A[i][i] - f * A[i][j]; } } for(int i = n-1; i >= 0; --i){ for(int j = i+1; j < n; ++j) A[i][n] -= A[j][n] * A[i][j]; A[i][n] /= A[i][i]; } } struct Trie { int sz,root,up;//sz include root but root's number is 0 int ch[maxnode][27],isend[maxnode],fail[maxnode]; void reset(int n) { sz=0;root=newnode();memset(fail,-1,sizeof(fail));up=n; } int newnode() { memset(ch[sz],-1,sizeof(ch[sz])); isend[sz++]=0; return sz-1; } void insert(char* s) { int len=strlen(s),u=root,c; for(int i=0;i<len;i++) { c=s[i]-'A'; if(ch[u]==-1) ch[u]=newnode(); u=ch[u]; } isend[u]=1; } void build() { int u; queue<int> Q; fail[root]=root; for(int i=0;i<up;i++) { if(ch[root][i]==-1) ch[root][i]=root; else { fail[ch[root][i]]=root; Q.push(ch[root][i]); } } while(!Q.empty()) { u=Q.front();Q.pop(); for(int i=0;i<up;i++) { if(ch[u][i]==-1) ch[u][i]=ch[fail[u]][i]; else { fail[ch[u][i]]=ch[fail[u]][i]; Q.push(ch[u][i]); } } } } void bfs() { int nxt; //double mul=1.0/up; for(int i=0;i<sz-1;i++) { A[i][i]=up; for(int j=0;j<up;j++) { nxt=ch[i][j]; A[i][nxt]-=1; } } A[sz-1][sz-1]=1;//X[sz-1]=0; } }; Trie T; int main() { int t,cs=0,n; char str[15]; scanf("%d",&t); while(t--) { if(cs) puts(""); scanf("%d %s",&n,str); cs++; printf("Case %d:\n",cs); memset(A,0,sizeof(A)); T.reset(n); T.insert(str); T.build(); T.bfs(); int len=strlen(str); for(int i=0;i<len;i++) X[i]=n; X[len]=0; equ=var=len+1; for(int i=0;i<len;i++) A[i][len+1]=n; Gauess(len+1); printf("%lld\n",(LL)(A[0][len+1]+0.5)); } return 0; }