TJOI2016 & HEOI2016 求和 (NKOJ 4026) 题解

感谢Wikipedia提供数学公式。题面
\begin{align} f(n)=\sum^n_{i=0}\sum^i_{j=0}S(i,j)\times2^i\times(j!) \end{align}
一个很直接的想法是去考虑把\(S(i,j)\)算出来,于是找到公式:

\begin{align} S(i,j)=\frac{1}{j!}\sum^j_{k=0}(-1)^{j-k}(^j_k)k^i=\sum^j_{k=0}\frac{(-1)^{j-k}k^i}{k!\times(j-k)!}\end{align}

注意到\(S(i,j)=0,\forall i<j\) ,所以

\begin{align} f(n)=\sum^n_{i=0}\sum^n_{j=0}S(i,j)\times2^j\times(j!)\end{align}

\(i=0\)\(j=0\) 的情况提出来,那么

\begin{align} f(n)=1+\sum^n_{i=1}\sum^n_{j=1}S(i,j)\times2^j\times(j!)\end{align}

固定 \(j\) 求和,有

\begin{align} f(n)=1+\sum^n_{j=1}2^j\times(j!)\sum^n_{i=1}S(i,j)\end{align}

\begin{align} f(n)=1+\sum^n_{j=1}2^j\times(j!)\sum^n_{i=1}\sum^j_{k=0}\frac{(-1)^{j-k}k^i}{k!\times(j-k)!}\end{align}

再交换 \(k\)\(i\) 求和的顺序

\begin{align} f(n)=1+\sum^n_{j=1}2^j\times(j!)\sum^j_{k=0}\frac{(-1)^{j-k}\sum^n_{i=1}k^i}{k!\times(j-k)!}\end{align}

观察右边的式子,稍做变换即是

\begin{align} \sum^j_{k=0}\frac{(-1)^{j-k}}{(j-k)!}\frac{\sum^n_{i=1}k^i}{k!}\end{align}

只需计算{\(\frac{(-1)^k}{k!}\)}与{\(\frac{\sum^n_{i=1}k^i}{k!}\)}的卷积,两个数列都可以在 \(O(n)\) 时间内处理出来(视 \(log(P)\) 为常数),卷积\(O(nlogn)\) ,再计算求和\(O(n)\),总时间复杂度 \(O(nlogn)\)

Code:

#include<cstdlib>
#include<cstring>
#include<cstdio>
#define swap(a,b) a^=b,b^=a,a^=b
typedef long long ll;
const int N=10000005;
const ll P=998244353,g=3;
ll ntt_gg[N]={1};
ll ksm(ll a,ll b) {
    ll o=1;
    if(a>=P) a%=P;if(b>=P-1) b%=P-1;
    for(;b;b>>=1,a=a*a%P)
    if(b&1) o=a*o%P;return o;
}
void NTT(ll A[],int n,int ty) {
    int i,j,k,m;ll t0,t1;
    for(i=0;i<n;i++) {
        for(j=0,k=i,m=1;
            m<n;m<<=1,k>>=1)
            j=(j<<1)|(k&1);
        if(i<j) swap(A[i],A[j]);
    }
    ntt_gg[0]=1;
    for(m=1;m<n;m<<=1) {
        t0=ksm(g,(P-1)+ty*(P-1)/(m<<1));
        for(i=1;i<m;i++) ntt_gg[i]=ntt_gg[i-1]*t0%P;
        for(k=0;k<n;k+=m<<1)
            for(i=k;i<k+m;i++) {
                t0=A[i];t1=A[i+m]*ntt_gg[i-k]%P;
                A[i]=t0+t1;A[i]-=A[i]>=P?P:0;
                A[i+m]=t0-t1;A[i+m]+=A[i+m]<0?P:0;
            }
    }
    if(ty==1) return;
    t0=ksm(n,P-2);
    for(i=0;i<n;i++) A[i]=A[i]*t0%P;
}
ll A[N],B[N],C[N],D[N];
int n,i,j,k,l=1 ;ll s,d,ans;
int main() {
    scanf("%d",&n);
    A[0]=A[1]=1;B[1]=n;
    for(i=2;i<=n;i++) A[i]=A[i-1]*ksm(i,P-2)%P;
    for(i=2;i<=n;i++) B[i]=ksm(i-1,P-2);
    for(i=2;i<=n;i++) B[i]=A[i-1]*(ksm(i,n)-1)%P*B[i]%P;
    for(i=1;i<=n;i++) if(i&1) A[i]=(P-1)*A[i]%P;
    while(l<=n) l<<=1;l<<=1;
    NTT(A,l,1);NTT(B,l,1);
    for(i=0;i<l;i++) A[i]=A[i]*B[i]%P;
    NTT(A,l,-1);s=d=ans=1;
    for(i=1;i<=n;i++) {
        s=s*i%P;
        d=(d<<1)%P;
        ans+=(s*d)%P*A[i]%P;
        ans-=ans>=P?P:0;
    }
    printf("%lld",ans);
}

 


posted @ 2017-07-15 23:47  SilentMelody  阅读(209)  评论(0编辑  收藏  举报