P4091 [HEOI2016/TJOI2016]求和

Posted dreagonm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4091 [HEOI2016/TJOI2016]求和相关的知识,希望对你有一定的参考价值。

留待警戒

FFT的时候长度要写的和函数里一样啊XD

瞎扯

这是个第二类斯特林数的理性愉悦颓柿子题目
颓柿子真的是让我hi到不行啦(才没有)

前置芝士

一个公式

[ sum_{i=0}^n t^i = frac{t^{n+1}-1}{t-1} ]

第二类斯特林数

第二类斯特林数的是指把n个对象放到m个集合里面的方案数
其递推式是
[ S_{n}^{m}=S_{n-1}^{m-1}+mS_{n-1}^{m} ]

容斥原理的得到的通式

[ S_n^m=frac{1}{m!}sum_{i=0}^m(-1)^{i}C_{m}^i(m-i)^n ]

颓柿子

题目要求求这样一个式子
[ f(n)=sum_{i=0}^nsum_{j=0}^iS_i^j imes2^j imes(j!) ]
然后我们把第二类斯特林数的通式代入进去
[ f(n)=sum_{i=0}^nsum_{j=0}^iS_i^j imes2^j imes(j!) ]
得到
[ f(n)=sum_{i=0}^nsum_{j=0}^i frac{1}{j!}sum_{k=0}^j(-1)^{k}C_{j}^k(j-k)^i imes2^j imes(j!)\=sum_{i=0}^nsum_{j=0}^ij! imes2^jsum_{k=0}^jfrac{(-1)^k}{k!} imesfrac{(j-k)^i}{(j-k)!}\=sum_{j=0}^nj! imes2^jsum_{k=0}^{j}frac{(-1)^k}{k!} imesfrac{sum_{i=0}^n(j-k)^i}{(j-k)!} ]
如果我们设(F(i)=frac{(-1)^k}{k!})(G(i)=frac{sum_{i=0}^n(j-k)^i}{(j-k)!}),则很容易就能看出一个卷积的形式,式子变形成
[ f(n)=sum_{j=0}^nj! imes 2^j sum_{i=0}^j F(i) imes G(j-i) ]
FFT求后面的式子就行了

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int MOD=998244353LL,G=3,invG=332748118;
int pow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)
            ans=(1LL*ans*a)%MOD;
        a=(1LL*a*a)%MOD;
        b>>=1;
    }
    return (ans%MOD+MOD)%MOD;
}
void FFT(int *a,int opt,int n){
    int lim=0;
    while((1<<lim)<n)
        lim++;
    for(int i=0;i<n;i++){
        int t=0;
        for(int j=0;j<lim;j++)
            if((i>>j)&1)
                t|=(1<<(lim-j-1));
        if(i<t)
            swap(a[t],a[i]);
    }
    for(int i=2;i<=n;i<<=1){
        int len=i/2;
        int tmp=pow((opt)?G:invG,(MOD-1)/i);
        for(int j=0;j<n;j+=i){
            int arr=1;
            for(int k=j;k<j+len;k++){
                int t=(a[k+len]*arr)%MOD;
                a[k+len]=((a[k]-t)%MOD+MOD)%MOD;
                a[k]=(a[k]+t)%MOD;
                arr=(arr*tmp)%MOD;
            }
        }
    }
    if(opt==0){
        int invn=pow(n,MOD-2);
        for(int i=0;i<n;i++)
            a[i]=(a[i]*invn)%MOD;
    }    
}
int a[300100],b[300100],n;
int jc[300100],inv[300100];
void init(void){
    jc[0]=inv[0]=1;
    for(int i=1;i<=n;i++){
        jc[i]=jc[i-1]*i%MOD;
        inv[i]=pow(jc[i],MOD-2);
    }
}
int f(int x){
    return ((((x&1)?-1:1)%MOD+MOD)%MOD*(inv[x]))%MOD;
}
int g(int x){
    if(x==1)
        return n+1;
    return ((((pow(x,n+1)-1)%MOD+MOD)%MOD)*pow(x-1+MOD,MOD-2)%MOD)*inv[x]%MOD;
}
signed main(){
    scanf("%lld",&n);
    // printf("n=%d
",n);
    init();
    for(int i=0;i<=n;i++)
        a[i]=f(i),b[i]=g(i);
    // for(int i=0;i<=n;i++)
    //     printf("f(%lld)=%lld g(%lld)=%lld
",i,a[i],i,b[i]);
    int lx=1;
    while(lx<=(n+n))
        lx<<=1;
    FFT(a,1,lx);
    FFT(b,1,lx);
    for(int i=0;i<lx;i++)
        a[i]=(a[i]*b[i])%MOD;
    FFT(a,0,lx);
    // for(int i=0;i<=n;i++)
    //     printf("f*g(%lld)=%lld
",i,a[i]);
    int ans=0;
    for(int i=0,j=1;i<=n;i++,j=(j+j)%MOD)
        ans=(ans+j*jc[i]%MOD*a[i]%MOD)%MOD;
    printf("%lld
",ans);
    return 0;
}

以上是关于P4091 [HEOI2016/TJOI2016]求和的主要内容,如果未能解决你的问题,请参考以下文章

P4091 [HEOI2016/TJOI2016]求和(第二类斯特林数,ntt)

[HEOI2016/TJOI2016]排序

P4093[HEOI2016/TJOI2016]序列

[HEOI2016/TJOI2016]求和

[HEOI2016/TJOI2016]排序 解题报告

[HEOI2016/TJOI2016]求和