本文参考:bztMinamoto露迭月巨佬的博客

前置知识:对生成函数有一定了解,有概率期望的一定基础。

定义:一个生成函数F(x),第i位表示某某为i的概率。

例题:[CTSC2006]歌唱王国

题意:

给定一个长度为的序列。然后每次掷一个平骰子(有m种值)并将其上的数字加入到初始为空的序列的末尾,如果序列中已经出现了给定序列,即的子串,则停止。

题解:

时间停止的概率,时间不停止的概率,,分别为它们的生成函数。

这其实是

考虑对这个式子做出变形,两边同时求导

,

考虑求出

介绍一个东西:对于一个长度为的序列,若,则称的一个

定义=

带入

求出即可。

代码:

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define gc getchar
#define int long long
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
const int N=1e5+5,P=1e4;
inline int add(int x,int y){return x+y>=P?x+y-P:x+y;}
inline int mul(int x,int y){return 1ll*x*y%P;}
int n,p,res,pos,bin[N],nxt[N],a[N];
signed main()
{
    p=read(),bin[0]=1;
    for(int i=1;i<=100000;i++)bin[i]=mul(bin[i-1],p);
    int T=read();
    while(T--)
    {
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        nxt[0]=nxt[1]=0;
        for(int i=2,j=0;i<=n;i++)
        {
            while(j&&a[j+1]!=a[i])j=nxt[j];
            j+=(a[j+1]==a[i]);
            nxt[i]=j;
        }
        pos=n,res=0;
        while(pos)
        {
            res=add(res,bin[pos]);
            pos=nxt[pos];
        }
        printf("%04lld\n",res);
    }
    return 0;
}

例题:[CTSC2006]歌唱王国

代码:

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define gc getchar
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
const int N=305;
const int P=1e9+7;
const double eps=1e-10;
double a[N][N],b[N];
char s[N];
int n,m,bin[N],h[N][N];
inline int Hash(int i,int l,int r){return ((h[i][r]-1ll*h[i][l-1]*bin[r-l+1])%P+P)%P;}
void Gauss(int n)
{
    for(int i=1;i<=n;i++)
    {
        if(a[i][i]>-eps&&a[i][i]<eps)
        {
            for(int j=i+1;j<=n;j++)if(a[j][i]<-eps||a[j][i]>eps)
            {
                for(int k=i;k<=n+1;k++)swap(a[i][k],a[j][k]);
                break;
            }
        }
        double t=1.0/a[i][i];
        for(int j=i;j<=n+1;j++)a[i][j]*=t;
        for(int j=i+1;j<=n;j++)
        {
            t=a[j][i];
            for(int k=i;k<=n+1;k++)a[j][k]-=a[i][k]*t;
        }
    }
    for(int i=n-1;i;i--)
        for(int j=i+1;j<=n;j++)a[i][n+1]-=a[j][n+1]*a[i][j];
}
int main()
{
    n=read();m=read();
    bin[0]=b[0]=1;
    for(int i=1;i<=m;i++)bin[i]=1ll*bin[i-1]*2%P,b[i]=b[i-1]*2;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)h[i][j]=(1ll*h[i][j-1]*2+(s[j]=='H'))%P;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            for(int k=1;k<=m;k++)(Hash(i,1,k)==Hash(j,m-k+1,m))?a[i][j]+=b[k]:0;
        a[i][n+1]=-1;
    }
    for(int i=1;i<=n;i++)a[n+1][i]=1;
    a[n+1][n+2]=1;
    Gauss(n+1);
    for(int i=1;i<=n;i++)printf("%.8lf\n",a[i][n+2]);
    return 0;
}