luogu P4548 [CTSC2006]歌唱王国

https://www.luogu.com.cn/problem/P4548
%yml 2018年的论文%%%
PGF入门题
设 f [ n ] 为 恰 好 在 第 n 次 结 束 的 概 率 , g [ n ] 为 在 第 n 次 之 后 结 束 的 概 率 设f[n]为恰好在第n次结束的概率,g[n]为在第n次之后结束的概率 f[n]ng[n]n
显然 g [ n ] = f [ n + 1 ] + g [ n + 1 ] g[n]=f[n+1]+g[n +1] g[n]=f[n+1]+g[n+1]
考虑生成函数,可以轻易得到
x G ( x ) + 1 = F ( x ) + G ( x ) \large xG(x)+1=F(x)+G(x) xG(x)+1=F(x)+G(x)
然后两边求导
G ( x ) + x G ′ ( x ) = F ′ ( x ) + G ′ ( x ) G(x)+xG'(x)=F'(x)+G'(x) G(x)+xG(x)=F(x)+G(x)
然后把1带进去可得
F ′ ( 1 ) = G ( 1 ) F'(1)=G(1) F(1)=G(1)
因为概率的生成函数求导后就是期望的生成函数,所以我们实际上要求的是 F ′ ( 1 ) = G ( 1 ) \large F'(1)=G(1) F(1)=G(1)
考虑在当前串后面拼上一个长度为m的串,设 o k [ i ] = [ [ 1... i ] = [ m − i + 1 , m ] ] ok[i]=[[1...i]=[m-i+1,m]] ok[i]=[[1...i]=[mi+1,m]]
G ( x ) × ( 1 c x ) m = ∑ i = 1 m o k [ i ] F ( x ) ( 1 c x ) m − i \large G(x)\times(\frac{1}{c}x)^m=\sum\limits_{i=1}^m ok[i]F(x)(\frac{1}{c}x)^{m-i} G(x)×(c1x)m=i=1mok[i]F(x)(c1x)mi
移项后可得
G ( 1 ) = ∑ i = 1 m o k [ i ] F ( 1 ) ( c x ) i G(1)=\sum\limits_{i=1}^m ok[i]F(1)(cx)^i G(1)=i=1mok[i]F(1)(cx)i
然后我们注意 F ( 1 ) = 1 F(1)=1 F(1)=1所以答案就是
G ( 1 ) = ∑ i = 1 m o k [ i ] c i G(1)=\sum\limits_{i=1}^m ok[i] c^i G(1)=i=1mok[i]ci
code:

#include<bits/stdc++.h>
#define N 200050
#define mod 10000
using namespace std;
int qpow(int x, int y) {
    int ret = 1;
    for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
    return ret;
}
int nxt[N], n, c, t, a[N], ha[6];
void solve() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i  ++) scanf("%d", &a[i]);
    for(int i = 2, j = 0; i <= n; i ++) {
        while(j && a[j + 1] != a[i]) j = nxt[j];
        if(a[j + 1] == a[i]) j ++;
        nxt[i] = j;
    }
    int ans = 0;
    for(int j = n; j; j = nxt[j]) ans = (ans + qpow(c, j)) % mod;
   // printf("%d\n", ans);
    for(int i = 1; i <= 4; i ++) ha[i] = ans % 10, ans /= 10;
    for(int i = 4; i >= 1; i --) printf("%d", ha[i]); printf("\n");
}
int main() {
    scanf("%d%d", &c, &t); c %= mod;
    while(t --) solve();
    return 0;
}
posted @ 2021-08-01 17:07  lahlah  阅读(33)  评论(0编辑  收藏  举报