zoukankan      html  css  js  c++  java
  • [CTSC2006]歌唱王国——生成函数

    题面

      Bzoj1152

    解析

      需要先来一手概率生成函数。

      定义概率生成函数$f(x)=sum_{i=0}^{infty}P(Y==i)x^i$,其中$P(Y==i)$表示$Y$这个变量取$i$的概率,容易发现$f(1) = 1$

      对该概率生成函数求导:$f'(x)=sum_{i=1}^{infty}P(Y==i)i*x^{i-1}$,那么可以发现$f'(1)$即是$Y$的期望


      接下来开始解决这道题。

      设$f_i$表示终止长度为$i$的概率,$F(x)$为其生成函数。设$g_i$表示长度为$i$还未终止的概率,$g_0=1$,$G(x)$为其生成函数。

      考虑$g_i$向$f_{i+1}$与$g_{i+1}$转移,即在长度为$i$的未终止的串后加一个字符:$g_i=f_{i+1}+g_{i+1}$,也即:$$F(x)+G(x)=x*G(x)+1$$

      因为$F'(1)$为所求,因此两边求导:$$F'(x)+G'(x)=x*G'(x)+G(x)$$

      代入$x=1$:$$F'(1)=G(1)$$

      现在只要求出$G(1)$即可

      设目标串串长为$m$,字符集大小为$n$,$a_i=1/0$表示$[1,i]$是否为目标串的一个$border$

      考虑在任意一个未终止串后加上一个目标串都一定可以终止,但可能在加到中间某个字符时就可以终止了,所以枚举真正所需要的串的长度,有方程:$g_i(frac{1}{n})^m=sum_{j=1}^{m}a_jf_{i+j}(frac{1}{n})^{m-j}$,即:$$G(x)(frac{1}{n})^m*x^m=F(x)sum_{i=1}^{m}a_i(frac{1}{n})^{m-i}*x^{m-i}$$

      代入$x=1$:$$G(1)=sum_{i=1}^m a_i*n^i$$

      $KMP$求出$a$数组即可

      $O(N)$

     代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 100005, mod = 10000;
    
    inline int read()
    {
        int ret, f=1;
        char c;
        while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
        ret=c-'0';
        while((c=getchar())&&(c>='0'&&c<='9'))ret=(ret<<3)+(ret<<1)+c-'0';
        return ret*f;
    }
    
    int add(int x, int y)
    {
        return x + y < mod? x + y: x + y - mod;
    }
    
    int n, m, T, a[maxn], fail[maxn], pw[maxn];
    
    void KMP()
    {
        int t;
        for(int i = 2; i <= m; ++i)
        {
            t = fail[i-1];
            while(t && a[t+1] != a[i])    t = fail[t];
            fail[i] = ((a[t+1] == a[i])? t + 1: 0);
        }
    }
    
    int main()
    {
        n = read(); T = read();
        pw[0] = 1;
        for(int i = 1; i <= 100000; ++i)
            pw[i] = pw[i-1] * n % mod;
        int ans;
        while(T --)
        {
            m = read();
            for(int i = 1; i <= m; ++i)
                a[i] = read();
            KMP();
            ans = 0;
            for(int i = m; i; i = fail[i])
                ans = add(ans, pw[i]);
            printf("%d%d%d%d
    ", ans / 1000, (ans / 100) % 10, (ans / 10) % 10, ans % 10);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    新手Android开发:onclicklistener到底怎么用?
    Myeclipse中web project 与java project区别
    <jsp:directive.page import=""/>的用法和解释
    怎样在myeclipse下,打开已有的项目
    有史以来最简单的三层实例(C#)
    show()跟showdialog()的区别
    献给和我一样的Java初学者——用UltraEdit代替“笨重”的IDE,实现轻巧编程!
    数据库连接错误——请求失败或服务器未及时响应
    说说二级C++
    十一张图让你轻松学会用VS打包
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/12639732.html
Copyright © 2011-2022 走看看