CTSC2006 歌唱王国

歌唱王国

problem

题解

\(f_i\) 表示 \(i\) 步结束的概率,\(g_i\) 表示 \(i\) 步未结束的概率。

\[ g_i=f_{i+1}+g_{i+1}\\ g_i(\frac{1}{m})^L=\sum_{j>i 且 j-i是\text{border}} f_j (\frac{1}{m})^{L-(j-i)} \]

第一个转移表示掷一次骰子dice会发生的事情。

第二个转移表示拼一个原串上去会发生的事情。(一定会结束)

solution1

solution2

https://jkloverdcoi.github.io/2019/12/13/bzoj-1152-%E6%AD%8C%E5%94%B1%E7%8E%8B%E5%9B%BD/
https://www.cnblogs.com/cjyyb/p/10649150.html

要求的是 \(F’(1)\) ,将 (1) 式两边对 \(x\) 求导后代入 \(x=1\),得到

\[ F’(x)+G’(x)=x\cdot G’(x)+G(x)\\ F’(1)=G(1) \]

\(x=1\) 代入 (2) 式,得到

扫描二维码关注公众号,回复: 8323034 查看本文章

\[ G(1)=m^L\sum_{i=1}^n a_i\cdot F(1) \cdot (\frac{1}{m})^{L-i}\\ G(1)=\sum_{i=1}^n a_i\cdot F(1) \cdot m^i\\ \]

注意到 \(F(1)=\sum f_i=1\),所以

\[ F’(1)=\sum_{i=1}^n a_i\cdot m^i \]

于是只需用 KMP 判断给定序列的每个前缀是不是它的 border 就可以了.

用 %04d 可以达到题目要求的输出效果,当然也可以自己写一下输出.

时间复杂度 \(O(n)\)

CO int N=1e5+10;
int pw[N];
int str[N],nxt[N];

void real_main(){
    int n=read<int>();
    for(int i=1;i<=n;++i) read(str[i]);
    for(int i=2;i<=n;++i){
        int j=nxt[i-1];
        while(j and str[j+1]!=str[i]) j=nxt[j];
        if(str[j+1]==str[i]) ++j;
        nxt[i]=j;
    }
    int ans=0;
    for(int i=n;i;i=nxt[i]) ans=add(ans,pw[i]);
    printf("%04d\n",ans);
}
int main(){
    int m=read<int>();
    pw[0]=1;
    for(int i=1;i<N;++i) pw[i]=mul(pw[i-1],m);
    for(int T=read<int>();T--;) real_main();
    return 0;
}

总结概率生成函数:

  • 优点:处理简洁,易扩展,⽐如可以改成求⽅差,或者说求某⼀项的值。

  • 缺点:列⽅程⽐较不直观,需要⼀定的套路积累和练习(+⼀个/+⼀组)。

猜你喜欢

转载自www.cnblogs.com/autoint/p/12103890.html