[HEOI2016/TJOI2016][bzoj4555] 求和 [斯特林数+NTT]

题面

传送门

思路

首先,我们发现这个式子中大部分的项都和\(j\)有关(尤其是后面的\(2^j\ast j!\)),所以我们更换一下枚举方式,把这道题的枚举方式变成先\(j\)再\(i\)

\(f(n)=\sum_{j=0}^n2^j\ast j!\sum_{i=0}^nS_i^j\)

第二类斯特林数有一个基于组合意义的公式:

\(S_i^j=\frac1{j!}\sum_{k=0}^j(-1)^kC_j^k(j-k)^i=\sum_{k=0}^j\frac{(-1)^k(j-k)^i}{k!(j-k)!}\)

把这个公式代回原式中,得到:

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

再次更换一下枚举方式,变成:

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

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

此时,设两个函数\(a\)和\(b\),令:

\(a(i)=\frac{(-1)^i}{i!}\)

\(b(i)=\frac{\sum_{j=0}^ni^j}{i!}=\frac{i^{n+1}-1}{(i-1)i!}\)

那么,

\(f(n)=\sum_{j=0}^n 2^j\ast j!\ast(a\ast b)(j)\)

其中(a\ast b)(j)表示\(a\)和\(b\)的\(0-j\)项的卷积

模数为\(998244353\),用\(NTT\)做一遍卷积即可,时间效率为\(O(nlog_2n)\)

注意事项

\(b(0)=1,b(1)=n+1\)

这两个要提前保存一下,因为用公式推的话会div 0

还有一个奇怪的问题我没有解决,具体看代码最后面吧

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
#define ll long long
ll MOD=998244353,g=3,inv[400010],f[400010],finv[400010];
int qpow(ll a,ll b){//快速幂
    ll re=1;
    while(b){
        if(b&1) re=re*a%MOD;
        a=a*a%MOD;b>>=1;
    }
    return re;
}
ll n,A[400010],B[400010],C[400010],r[400010],limit,cnt;
void ntt(ll *a,ll type){
    int i,j,k,mid;ll y,w,wn;
    for(i=0;i<limit;i++) if(i<r[i]) swap(a[i],a[r[i]]);
    for(mid=1;mid<limit;mid<<=1){
        wn=qpow((type==1)?g:inv[g],(MOD-1)/(mid<<1));
        for(j=0;j<limit;j+=(mid<<1)){
            w=1;
            for(k=0;k<mid;k++,w=w*wn%MOD){
                y=a[j+k+mid]*w%MOD;
                a[j+k+mid]=(a[j+k]-y+MOD)%MOD;
                a[j+k]=(a[j+k]+y)%MOD;
            }
        }
    }
    if(type==-1) for(i=0;i<limit;i++) a[i]=a[i]*inv[limit]%MOD;
}
void init(){
    limit=1;cnt=0;int i;
    while(limit<=(n<<1)) limit<<=1,cnt++;
    for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1)));
    inv[1]=A[0]=B[0]=f[1]=finv[1]=1;A[1]=MOD-1;B[1]=n+1;
    for(i=2;i<=limit;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
    for(i=2;i<=limit;i++){
        f[i]=f[i-1]*i%MOD;
        finv[i]=finv[i-1]*inv[i]%MOD;
    }
}
int main(){
    n=read();
    init();int i;
    for(i=2;i<=n;i++) A[i]=(((i%2)?-1:1)*finv[i]+MOD)%MOD;
    for(i=2;i<=n;i++) B[i]=((qpow(i,n+1)-1)*inv[i-1]%MOD*finv[i])%MOD;
    ntt(A,1);ntt(B,1);
    for(i=0;i<limit;i++) C[i]=A[i]*B[i]%MOD;
    ntt(C,-1);
    ll ans=0;
    for(i=0;i<=n;i++) ans=(ans+qpow(2,i)*f[i]%MOD*C[i]%MOD)%MOD;
    printf("%lld\n",(ans+1)%MOD);//这里不知道为什么,一定要加个1,我也没有搞明白
}

原文地址:https://www.cnblogs.com/dedicatus545/p/9152505.html

时间: 2024-10-09 04:13:49

[HEOI2016/TJOI2016][bzoj4555] 求和 [斯特林数+NTT]的相关文章

[HEOI2016/TJOI2016]求和 斯特林数 + NTT

Description 计算函数的值 \[f(n) = \sum \limits_{i=0}^{n} \sum \limits_{j=0}^{i} 2^j \times j! \times S(i,j)\] Solution 大家好,我是练习推柿子半天的个人练习生\(newbielyx\). \[ f(n) = \sum \limits_{i=0}^{n} \sum \limits_{j=0}^{i} 2^j \times j! \times S(i,j) \] \[ = \sum \limit

【BZOJ】4555: [Tjoi2016&amp;Heoi2016]求和 排列组合+多项式求逆 或 斯特林数+NTT

[题意]给定n,求Σi=0~nΣj=1~i s(i,j)*2^j*j!,n<=10^5. [算法]生成函数+排列组合+多项式求逆 [题解]参考: [BZOJ4555][Tjoi2016&Heoi2016]求和-NTT-多项式求逆 $ans=\sum_{i=0}^{n}\sum_{j=0}^{i}s(i,j)*2^j*j!$ 令$g(n)=\sum_{j=0}^{n}s(n,j)*2^j*j!$ 则ans是Σg(i),只要计算出g(i)的生成函数就可以统计答案. g(n)可以理解为将n个数划分

BZOJ4555 [Tjoi2016&amp;Heoi2016]求和 【第二类斯特林数 + NTT】

题目 在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心. 现在他想计算这样一个函数的值: S(i, j)表示第二类斯特林数,递推公式为: S(i, j) = j ? S(i ? 1, j) + S(i ? 1, j ? 1), 1 <= j <= i ? 1. 边界条件为:S(i, i) = 1(0 <= i), S(i, 0) = 0(1 <= i) 你能帮帮他吗? 输入格式 输入只有一个正整数 输出格式 输出f(n).由于结果会很大,输出f(n)对998244353(7

bzoj 5093 图的价值 —— 第二类斯特林数+NTT

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5093 每个点都是等价的,从点的贡献来看,得到式子: \( ans = n * \sum\limits_{d=0}^{n-1} d^{k} * 2^{C_{n-1}^{2}} * C_{n-1}^{d} \) 使用 \( n^{k} = \sum\limits_{i=0}^{k} S(k,i) * i! *C_{n}^{i} \) 得到 \( ans = n * \sum\limits_{d

bzoj5093:图的价值(第二类斯特林数+NTT)

传送门 首先,题目所求为\[n\times 2^{C_{n-1}^2}\sum_{i=0}^{n-1}C_{n-1}^ii^k\] 即对于每个点\(i\),枚举它的度数,然后计算方案.因为有\(n\)个点,且关于某个点连边的时候剩下的边都可以随便连,所以有前面的两个常数 所以真正要计算的是\[\sum_{i=0}^{n-1}C_{n-1}^ii^k\] 根据第二类斯特林数的性质,有\[i^k=\sum_{j=0}^iS(k,j)\times j!\times C_i^j\] 然后带入,得\[\s

bzoj 4555 [Tjoi2016&amp;Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化

[Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 679  Solved: 534[Submit][Status][Discuss] Description 在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心. 现在他想计算这样一个函数的值: S(i, j)表示第二类斯特林数,递推公式为: S(i, j) = j ∗ S(i − 1, j) + S(i − 1, j − 1), 1 <= j &l

【BZOJ 4555】[Tjoi2016&amp;Heoi2016]求和 NTT+第二类斯特林数

用到第二类斯特林数的性质,做法好像很多,我打的是直接ntt,由第二类斯特林数的容斥公式可以推出,我们可以对于每一个i,来一次ntt求出他与所有j组成的第二类斯特林数的值,这个时候我们是O(n^2logn)的,还不如暴力,但是我们发现,对于刚刚提到的容斥的式子,将其化为卷积形式后,其一边的每一项对于每一个i都相同,另一边的每一项是对于所有的i形成一个n项的等比数列,这样我们可以把成等比数列的一边求和,用固定的一边去卷他们的和,这时候的答案的每一项就是所有的i的这一项的和,然后我们再O(n)乘上阶乘

【BZOJ4555】求和(第二类斯特林数,组合数学,NTT)

[BZOJ4555]求和(第二类斯特林数,组合数学,NTT) 题面 BZOJ 题解 推推柿子 \[\sum_{i=0}^n\sum_{j=0}^iS(i,j)·j!·2^j\] \[=\sum_{i=0}^n\sum_{j=0}^nS(i,j)·j!·2^j\] \[=\sum_{i=0}^n\sum_{j=0}^nj!·2^j(\frac{1}{j!}\sum_{k=0}^j(-1)^k·C_j^k·(j-k)^i)\] \[=\sum_{j=0}^n2^j\sum_{k=0}^j(-1)^k

[HEOI2016/TJOI2016]求和——第二类斯特林数

给你斯特林数就换成通项公式,给你k次方就换成斯特林数 考虑换成通项公式之后,组合数没有什么好的处理方法 直接拆开,消一消阶乘 然后就发现了(j-k)和k! 往NTT方向靠拢 然后大功告成 其实只要想到把斯特林公式换成通项公式,考虑用NTT优化掉(j-k)^i 后面都是套路了. #include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') #define int long long