CTS2019珍珠

不难发现我们需要一个选奇数/偶数个的egf
这个分别是 $\frac {e^x - e^{-x}} {2} $ 和 $\frac {e^x + e^{-x}} {2} $。

然后就可以开始推式子了。

答案是

\[ n!\sum _{k=0}^{n-2m}(\frac {e^x + e^{-x}} {2}+y\frac {e^x - e^{-x}} {2})^D [x^n][y^k] \]

\[ = n! \frac {1}{2^D} \sum _{k=0}^{n-2m} \sum _{i=0}^D e^{(2i-D)x} (1+y)^i(1-y)^{D-i}[x^n][y^k] \]

\[ = \frac {1}{2^D} \sum_{i=0}^D \binom {D}{i}(2i-D)^n \sum _{k=0}^{n-2m} (1+y)^i(1-y)^{D-i}[y^k] \]

好了,考虑如何计算这个东西。

首先将\((1-y)^D\)计算出来,因为$ (1+y)/(1-y) = 1 + 2y + 2y^2 + 2y^3 + ...$

\(lim = n-2m\)

我们可以轻易的算出贡献

枚举i, 枚举有多少次是2(至少多加了1)

有:
\[ ans*2^D = \sum _{i=0}^D \binom {D}{i} (2i-D)^n \sum_p^D ff[p] \sum_{k=0}^D \binom {lim-p}{k} 2^k \binom{i}{k} \]

交换第二三个和号,并且将只与一个变量相关的弄到一起,最后会形成如下形式:

\[ ans*2^D = \sum _{i=0}^D A(i) \sum_p^D B(p) \frac{1}{(i-p)!}\sum_{k=0}^D C(k) \frac{1}{(lim-p-k)!} \]

其中,\(A,B,C\)是三个多项式

将sigma_p后的部分当作f(p),f(p)可以通过C与\(e^x\)卷积得到,之后再卷积一次就能得出答案

复杂度一个log

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353,g=3;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
const int inv2=qpow(2,mod-2);
/* math */
typedef vector<int> poly;
namespace poly_template{
    int rev[4000010];
    void DFT(int *t,int n,int type){
        int l=0;while(1<<l<n)++l;
        for(int i=1;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        for(int i=0;i<n;i++)if(i<rev[i])swap(t[i],t[rev[i]]);
        for(int step=1;step<n;step<<=1){
            int wn=qpow(g,(mod-1)/(step<<1));
            for(int i=0;i<n;i+=step*2)for(int j=0,w=1;j<step;j++,w=mul(w,wn)){
                int x=t[i+j],y=mul(w,t[i+j+step]);
                t[i+j]=add(x,y),t[i+j+step]=sub(x,y);
            }
        }
        if(type==1)return ;for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
        int inv=qpow(n,mod-2);for(int i=0;i<n;i++)t[i]=mul(t[i],inv);
    }
    inline poly NTT(poly A,int n,poly B,int m){
        poly ret;
        int l=0;while(1<<l<n+m)++l;
        A.resize(1<<l),B.resize(1<<l),ret.resize(1<<l);
        DFT(&A[0],1<<l,1);DFT(&B[0],1<<l,1);
        for(int i=0;i<1<<l;i++)ret[i]=mul(A[i],B[i]);
        DFT(&ret[0],1<<l,-1);
        ret.resize(n+m-1);
        return ret;
    }
    inline poly NTT(poly A,poly B){return NTT(A,A.size(),B,B.size());}
}
using namespace poly_template;
int D,n,m;

int fac[4000010],ifac[4000010];
inline void binom_init(int n=4000000){
    fac[0]=ifac[0]=1;for(int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
    ifac[n]=qpow(fac[n],mod-2);for(int i=n-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
}
inline int binom(int a,int b){
    if(b>a)return 0;
    return mul(fac[a],mul(ifac[b],ifac[a-b]));
}
poly G,ff,Fac,F;

int main()
{
    binom_init();
    cin >> D >> n >> m;
    if(n<2*m){printf("%d\n",0);return 0;}
    if(D<=n-2*m+1){printf("%d\n",qpow(D,n));return 0;}
    ff.resize(D+1);G.resize(D+1);Fac.resize(D+1);F.resize(D+1);
    int lim=n-2*m;
    for(int i=0;i<=min(D,n-2*m);i++){
        ff[i]=binom(D,i);
        if(i&1)ff[i]=mod-ff[i];
        ff[i]=mul(ff[i],fac[lim-i]);
    }
    for(int i=0;i<=D;i++)G[i]=mul(qpow(2,i),mul(ifac[i],ifac[i])), Fac[i]=ifac[i];
    ff=NTT(ff,Fac);
    for(int i=0;i<=D;i++)G[i]=mul(G[i],lim-i>=0?ff[lim-i]:0);
    for(int i=0;i<=D;i++)F[i]=mul(mul(fac[D],ifac[D-i]),qpow(1ll*(mod+2*i-D)%mod,n));
    G=NTT(Fac,G);
    int ans=0;
    for(int i=0;i<=D;i++){
        ans=add(ans,mul(F[i],G[i]));
    }
    ans=mul(ans,qpow(inv2,D));
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/weiyanpeng/p/10961497.html
今日推荐