其他分享
首页 > 其他分享> > P4091 [HEOI2016/TJOI2016]求和

P4091 [HEOI2016/TJOI2016]求和

作者:互联网

首先,我们需要知道第二类斯特林数组的组合意义(即容斥)

$S^m_n = \frac{1}{m!} \sum_{k = 0}^{m}(-1)^kC^k_m(m - k)^n$
然后,题目中让我们求

$f(n) = \sum_{i = 0}^n\sum_{j = i}^nS^j_i2^jj!$

我们直接将$S^j_i$展开成上述的组合意义,同时$j$从$0$开始枚举(因为当$m > n$时,$S^m_n = 0$)

则有:

$f(n) = \sum_{i = 0}^n\sum_{j = 0}^n\frac{1}{j!}\sum_{k = 0}^j(-1)^kC^k_j (j - k)^i * 2^j*j!$
我们发现$j!$可以约去,同时将$C^k_j$展开,$2^j$提到前边:

$=\sum_{i = 0}^n\sum_{j = 0}^n2^j\sum_{k = 0}^j(-1)^k * \frac{j!}{k! * (j - k)!}*(j - k) ^ i$

我们再讲$j!$提到前边,同时底数相同的化一下

$=\sum_{i= 0}^n\sum_{j = 0}^n2^j * j!\sum_{k= 0}^j \frac{(-1)^k}{k!}\frac{(j - k)^i}{(j - k)!}$

我们将第一个$\sum$化到后面

$\sum_{j = 0}^n2^j*j!\sum_{k=0}^j\frac{(-1)^k}{k!}\frac{\sum_{i = 0}^n(j - k)^i}{(j- k)!}$

根据等比数列求和公式

$\sum_{i = 0}^n(j - k)^i = \frac{1 - (j - k)^{n + 1}}{1 - (j - k)}$

我们设

$f(i) = \frac{(-1)^i}{i!},g(i) = \frac{1 - i^{n + 1}}{(1 - i)*i!}$
那么则有

上式$=\sum_{j = 0}^n2^jj!\sum_{k = 0}^j f(k)g(j - k)$

发现,这是个卷积啊,直接上NTT就好了

#include<cstdio>
#include<iostream>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int N = 8e5 + 3;
const LL mod = 998244353;
LL n;
LL a[N],b[N];
LL fac[N];
LL p[N];
int r[N],l,limit = 1;
inline LL quick(LL a,LL b){
    LL res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;    
    }
    return res;
}
inline void nttle(LL *A,int type){
    for(int i = 0;i < limit;++i) 
        if(i < r[i]) swap(A[i],A[r[i]]);
    for(int mid = 1;mid < limit;mid <<= 1){
        LL Wn = (type == 1) ? quick(3,(mod - 1) / (mid << 1)) : 
        quick(3,mod - 1 - (mod - 1) / (mid << 1));
        for(int R = mid << 1,j = 0;j < limit;j += R){
            LL w = 1;
            for(int k = 0;k < mid;++k,w = w * Wn % mod){
                LL x = A[j + k],y = w * A[j + mid + k] % mod;
                A[j + k] = x + y;
                A[j + mid + k] = x - y;
                if(A[j + k] >= mod) A[j + k] -= mod;
                if(A[j + mid + k] < 0) A[j + mid + k] += mod;
            }
        }
    }
    if(type == -1){
        LL inv = quick(limit,mod - 2);
        for(int i = 0;i < limit;++i) A[i] = A[i] * inv % mod;
    }
}
int main(){
    scanf("%lld",&n);
    p[0] = fac[0] = 1;
    for(LL i = 1;i <= n;++i){
        p[i] = (p[i - 1] << 1) % mod;
        fac[i] = fac[i - 1] * i % mod; 
    }
    for(LL i = 0;i <= n;++i){
        if(i & 1) a[i] = (-1 + mod) * quick(fac[i],mod - 2) % mod;
        else a[i] = 1 * quick(fac[i],mod - 2) % mod;
        b[i] = (quick(i,n + 1) - 1 + mod) % mod * quick((i - 1 + mod) % mod * fac[i] % mod,mod - 2) % mod;
    }
    b[0] = 1,b[1] = n + 1;
 // for(int i = 0;i <= n;++i) printf("%lld ",a[i]);puts("");
 // for(int i = 0;i <= n;++i) printf("%lld ",b[i]);puts("");
    while(limit < 2 * (n + 1)) limit <<= 1,++l;
    for(int i = 0;i < limit;++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
     //printf("%d ",r[i]);puts("");
    nttle(a,1);nttle(b,1);
    for(int i = 0;i < limit;++i) a[i] = a[i] * b[i] % mod;
    nttle(a,-1);
    LL ans = 0;
 // for(int i = 0;i <= n;++i) printf("%lld ",a[i]);
    for(int i = 0;i <= n;++i)
        ans = (ans + p[i] * fac[i] % mod * a[i] % mod) % mod;   
    printf("%lld\n",ans);
    return 0;   
}

标签:frac,int,sum,P4091,TJOI2016,HEOI2016,include,LL,mod
来源: https://www.cnblogs.com/wyxdrqc/p/10627544.html