[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)对998244353(7 × 17 × 223 + 1)取模的结果即可。

1 ≤ n ≤ 100000

Sample Input

3

Sample Output

87

我们知道第二类斯特林数和排列数(下降幂)组合在一起可以表示n^k,又因为排列等于组合乘上一个阶乘,于是我们就可以开开心心的二项式反演,得到一个某一行(其实也可以很多行,鉴于这个式子的特殊性质,我们可以把不同行的同一列合并)某一列的斯特林数的表达式。

具体的说,S(k,n) = Σ (i^k / i!) * ((-1)^(n-i) / (n-i)!)     [具体推导就不写了,就是一个二项式反演]。

这个式子的特殊性质太多了,首先它是一个卷积的形式,所以我们可以直接用NTT 在 N log N 的时间求出某一行的所有第二类斯特林数分别是多少;

并且只有 i^k 项和行数有关,所以同一列很好合并,于是这个题就做完了2333。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=330005;
const int ha=998244353;
const int root=3,inv=ha/3+1;
int a[maxn],b[maxn],jc[maxn];
int r[maxn],N,M,n,INV,l;

inline int add(int x,int y){
	x+=y;
	return x>=ha?x-ha:x;
}

inline int ksm(int x,int y){
	int an=1;
	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
	return an;
}

inline void NTT(int *c,const int f){
	for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]);

	for(int i=1;i<N;i<<=1){
		int omega=ksm(f==1?root:inv,(ha-1)/(i<<1));
		for(int p=i<<1,j=0;j<N;j+=p){
			int now=1;
			for(int k=0;k<i;k++,now=now*(ll)omega%ha){
				int x=c[j+k],y=c[j+k+i]*(ll)now%ha;
				c[j+k]=add(x,y);
				c[j+k+i]=add(x,ha-y);
			}
		}
	}

	if(f==-1) for(int i=0;i<N;i++) c[i]=c[i]*(ll)INV%ha;
}

inline void init(){
	jc[0]=1;
	for(int i=1;i<=n;i++) jc[i]=jc[i-1]*(ll)i%ha;
	for(int i=0;i<=n;i++){
		if(!i) a[i]=1;
		else if(i==1) a[i]=n+1;
		else a[i]=add(ksm(i,n+1),ha-1)*(ll)ksm(add(i,ha-1)*(ll)jc[i]%ha,ha-2)%ha;
		if(i&1) b[i]=ha-ksm(jc[i],ha-2);
		else b[i]=ksm(jc[i],ha-2);
	}

	M=n<<1;
	for(N=1;N<=M;N<<=1) l++;
	for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}

inline void solve(){
	NTT(a,1),NTT(b,1);
	for(int i=0;i<N;i++) a[i]=a[i]*(ll)b[i]%ha;
	INV=ksm(N,ha-2),NTT(a,-1);
}

inline void output(){
	int ans=0,base=1;
	for(int i=0;i<=n;i++,base=add(base,base)) ans=add(ans,a[i]*(ll)base%ha*(ll)jc[i]%ha);
	printf("%d\n",ans);
}

int main(){
	scanf("%d",&n);
	init();
	solve();
	output();
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8640895.html

时间: 2024-11-09 10:49:50

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

[题解] 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\),

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

[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

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_{

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!

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