NFLSPC #1 String

Link
一个串是合法串当且仅当满足下列条件中的至少一个:
\(1.\)它是空串。
\(2.\)它首尾字母相同且去掉首尾字母之后是合法串。
\(3.\)它可以从某个位置切开得到两个合法串。
\(f_i\)表示长度为\(i\)的合法串个数,\(g_i\)表示长度为\(i\)的仅满足第\(2\)个条件的串的个数。
显然初始状态为\(f_0=1,g_0=0\),转移为:

\[\begin{aligned} f_i&=\sum f_jg_{i-j}\\ g_i&=mf_{i-2}-\frac1m\sum g_jg_kf_{i-j-k} \end{aligned} \]

注意到有意义的下标都是偶数,因此我们令\(i\leftarrow\frac i2\)
考虑其OGF\(F(x),G(x)\),那么\(F=FG+1,G=mxF+\frac1mG^2F\)
那么\(F(x)=\frac{m+2-m\sqrt{1-4x-4mx}}{2(m^2x+1)}\),直接\(O(n)\)计算\([x^n]F(x)\)即可。

#include<cstdio>
const int N=200007,P=998244353;
int a[N],inv[N];
int mod(int x){return x+(x>>31&P);}
int pow(int a,int b){int r=1;for(;b;b>>=1,a=1ll*a*a%P)if(b&1)r=1ll*a*r%P;return r;}
int main()
{
    int n,m,k,ans=0,x;
    scanf("%d%d",&n,&m);
    if(n&1) return puts("0"),0;
    if(m==1) return puts("1"),0;
    n/=2,inv[0]=inv[1]=1;
    for(int i=2;i<=n||i<=2;++i) inv[i]=1ll*(P-P/i)*inv[P%i]%P;
    a[0]=1,k=1ll*pow(m-1,P-2)*m%P*inv[2]%P;
    for(int i=1;i<=n;++i) a[i]=1ll*a[i-1]*mod(4*i-6)%P*inv[i]%P;
    a[0]=mod(a[0]-pow(k,P-2)+1),x=pow(mod(1-k-k+P),P-2);
    for(int i=0,pw=1,base=1ll*k*k%P*(P-4)%P*x%P;i<=n;++i) ans=(ans+1ll*pw*a[n-i])%P,pw=1ll*pw*base%P;
    ans=1ll*ans*pow(m-1,n)%P*x%P*(P-k)%P;
    printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/12926616.html