[CTSC2006]歌唱王国

[SDOI2017]硬币游戏的弱化版

但是也不完全一样

按照硬币游戏的题,$F(x)=\sum a_i x^i$来刻画第i位结尾的概率生成函数

然后$G(x)$表示以i结尾,前面的随便选。$P(x)$表示前缀后缀的匹配

$F=G-F*(G+P)$然后G变成形式幂级数,分母乘过去,求导。

但是,这个题是**期望**而不是**概率**,

$F(x)=\sum a_i ×i× x^i$把$(1/|\Sigma|)$带入才是答案

i怎么出来呢?

求导!再集体乘上x!

也就是说,我们求的答案其实是:$(1/|\Sigma|)F'(1/|\Sigma|)$

对于刚才$F=G-F*(G+P)$求导之后,把$F'$移项过去,然后对着凑就可以了。

注意,虽然mod 1e4,但是n*n还是爆int的

 代码:

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define int long long
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1e5+5;
const int mod=1e4;
int s[N];
int m;
int n;
ll mi[N];
int nxt[N];
int qm(int x,int y){
    int ret=1;
    while(y){
        if(y&1) ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}
int kmp(){
    memset(nxt,0,sizeof nxt);
    nxt[1]=0;
    for(reg i=2,j=0;i<=m;++i){
        while(j&&s[j+1]!=s[i]) j=nxt[j];
        if(s[j+1]==s[i]) ++j;
        nxt[i]=j;
    }
    int ret=0;
    int st=m;
    while(nxt[st]){
        ret=(ret+mi[nxt[st]])%mod;
        st=nxt[st];
    }
    return ret;
}
int main(){
    int t;
    rd(n);rd(t);
    mi[0]=1;
    for(reg i=1;i<=1e5;++i) mi[i]=mi[i-1]*n%mod;
    
    while(t--){
        rd(m);
        for(reg i=1;i<=m;++i) rd(s[i]);
        int P=kmp();
        int m1=qm(n,m);//,m2=qm(n,2*m-2);
        ll ans=(m1+P)%mod;
        printf("%04lld\n",ans);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/23 18:09:25
*/

求导得到i这一步值得积累。

求导不光能降次,还能把指数扔下来,也许还很有用!

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10424478.html
今日推荐