题目链接:https://vjudge.net/problem/UVALive-3490

题意:随机字母组成一个串,有一个目标串,当这个由随机字母组成的串出现目标串就停止,求这个随机字母

组成串的期望长度。

解法:容易看出,dp[i] = 所有他下一步可能的节点dp[j]之和/m+1。可以想一下从头走到i的递推式,是dp[i]

= 所有走到i这个节点的dp[j]+1。

然后就可以列出n个方程,dp[最后一个节点] = 0。然后用高斯消元求解。double会有误差,所以用了整数

的,做法很简单,把方程式子左右乘个m,然后消元的时候比如第一行是3,第二行那个位置系数是2,那么对

于后面的系数x1(第一行),x2(第二行),x2*3-x1*2即可。

///UVALVE 3490

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 20;
struct Matrix{
    LL m[20][20];
}x;
struct AhoCorasick{
    int sz, ch[maxn][26], val[maxn], f[maxn];
    void clear(){
        memset(ch[0], 0, sizeof(ch[0]));
        sz=1;
    }
    int idx(char c){return c-'A';}
    void insert(char *s){
        int u=0, n=strlen(s);
        for(int i=0; i<n; i++){
            int c=idx(s[i]);
            if(!ch[u][c]){
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=1;
    }
    void getfail(){
        queue<int>q;
        f[0]=0;
        for(int c=0;c<26;c++){
            int u=ch[0][c];
            if(u){
                f[u]=0;
                q.push(u);
            }
        }
        while(!q.empty()){
            int r=q.front();q.pop();
            for(int c=0; c<26; c++){
                int u=ch[r][c];
                if(!u){
                    ch[r][c]=ch[f[r]][c];
                    continue;
                }
                q.push(u);
                int v=f[r];
                while(v&&!ch[v][c]) v=f[v];
                f[u]=ch[v][c];
            }
        }
    }
    void Getmaze(int num, int n){
        memset(x.m, 0, sizeof(x.m));
        for(int i=0; i<n-1; i++){
            x.m[i][n]-=num;
            x.m[i][i]-=num;
            for(int j=0; j<num; j++) x.m[i][ch[i][j]]++;
        }
        x.m[n-1][n-1]=1;
        x.m[n-1][n]=0;
    }
}AC;

void Guass(int n){
    int i, j, k, r;
    for(i=0; i<n; i++){
        r=i;
        while(r<n && !x.m[r][i]) r++;
        if(r!=i) for(j=0; j<=n; j++) swap(x.m[r][j], x.m[i][j]);
        for(k=i+1; k<n; k++){
            LL f=x.m[k][i]/x.m[i][i];
            for(j=i;j<=n;j++) x.m[k][j]-=f*x.m[i][j];
        }
    }
    for(i=n-1; i>=0; i--){
        for(j=i+1; j<n; j++){
            x.m[i][n]-=x.m[j][n]*x.m[i][j];
        }
        x.m[i][n]/=x.m[i][i];
    }
}

int main(){
    int n,t,ks=0;
    char s[15];
    scanf("%d", &t);
    while(t--){
        printf("Case %d:\n", ++ks);
        scanf("%d%s", &n,s);
        int len=strlen(s)+1;
        AC.clear();
        AC.insert(s);
        AC.getfail();
        //puts("lsx");

        AC.Getmaze(n,len);
        Guass(len);
        printf("%lld\n", x.m[0][len]);
        if(t!=0) printf("\n");
    }
    return 0;
}