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}^n\sum_{j=0}^iS_i^j\times2^j\times(j!)
\]
然后我们把第二类斯特林数的通式代入进去
\[
f(n)=\sum_{i=0}^n\sum_{j=0}^iS_i^j\times2^j\times(j!)
\]
得到
\[
f(n)=\sum_{i=0}^n\sum_{j=0}^i \frac{1}{j!}\sum_{k=0}^j(-1)^{k}C_{j}^k(j-k)^i\times2^j\times(j!)\\=\sum_{i=0}^n\sum_{j=0}^ij!\times2^j\sum_{k=0}^j\frac{(-1)^k}{k!}\times\frac{(j-k)^i}{(j-k)!}\\=\sum_{j=0}^nj!\times2^j\sum_{k=0}^{j}\frac{(-1)^k}{k!}\times\frac{\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!\times 2^j \sum_{i=0}^j F(i)\times 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",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\n",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\n",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\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/dreagonm/p/10435299.html

时间: 2024-10-09 04:15:47

P4091 [HEOI2016/TJOI2016]求和的相关文章

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

题面:https://www.luogu.org/problem/P4091 题解:\[\begin{array}{l}f(n) = \sum\limits_{i = 0}^n {\sum\limits_{j = 0}^i {{\rm{S}}(i,j) \cdot {2^{\rm{j}}} \cdot j!} } \\ = \sum\limits_{i = 0}^n {\sum\limits_{j = 0}^n {{\rm{S}}(i,j) \cdot {2^{\rm{j}}} \cdot j!

luogu P4091 [HEOI2016/TJOI2016]求和

传送门 这一类题都要考虑推式子 首先,原式为\[f(n)=\sum_{i=0}^{n}\sum_{j=0}^{i}S(i,j)*2^j*j!\] 可以看成\[f(n)=\sum_{j=0}^{n}2^j*j!\sum_{i=j}^{n}S(i,j)\] 又因为\[S(i,j)=\frac{1}{j!}\sum_{k=0}^{j}(-1)^k*\binom{j}{k}*(j-k)^i\] 所以\[f(n)=\sum_{j=0}^{n}2^j*j!\sum_{i=0}^{n}\frac{1}{j!}

[题解] LuoguP4091 [HEOI2016/TJOI2016]求和

传送门 首先我们来看一下怎么求\(S(m,n)\). 注意到第二类斯特林数的组合意义就是将\(m\)个不同的物品放到\(n\)个没有区别的盒子里,不允许有空盒子的方案数. 那么将\(m\)个不同的物品随便扔到\(n\)个盒子里的方案数就是\(n^m\),这里盒子也有区别了. 那么枚举有多少盒子有物品,然后斯特林数安排一下,注意到这是的盒子是没有区别的,再排列就好了,即 \[ n^m=\sum\limits_{i=0}^n \binom{n}{i}S(m,i)i! \] 但我们要求的是\(S\),

[HEOI2016/TJOI2016]求和

Discription 在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) 你能帮帮他吗? Input 输入只有一个正整数 Output 输出f(n). 由于结果会很大,输出f(n

[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

[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

[HEOI2016/TJOI2016]排序 解题报告

[HEOI2016/TJOI2016]排序 题意 给出一个大小为 \(n\) 的排列, 对这个排列进行 \(m\) 次操作, 操作分为以下两种, 0 l r 表示将区间 \([l,r]\) 的数升序排序. 1 l r 表示将区间 \([l,r]\) 的数降序排序. 询问 \(m\) 次操作后下标为 \(q\) 的数字. 思路 不看题解打死也想不出来系列 考虑二分答案. 设当前二分的答案为 \(mid\), 把原排列中 大于等于 \(mid\) 的数标记为 \(1\), 小于 \(mid\) 的数

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树) 题面 给出一个长度为\(n\)的字符串\(s\),以及\(m\)组询问.每个询问是一个四元组\((a,b,c,d)\),问\(s[a,b]\)的所有子串和字符串\(s[c,d]\)的最长公共前缀长度的最大值. \(n,m \leq 10^5\) 分析 显然答案有单调性.首先我们二分答案\(mid\),考虑如何判定. 如果mid这个答案可行,那么一定存在一个后缀x,它的开头在\([a,

[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!