求 \(10^5\) 以内的所有贝尔数:将 \(n\) 个有标号的球划分为若干非空集合的方案数

Solution

非空集合的指数生成函数为 \(F(x)=e^x-1\)

枚举一共用多少个集合,答案就是求这些集合的组合(无顺序),于是 \(G(x)=\sum_{i=0}^{\infty} \frac{F^i(x)}{i!}=e^{F(x)}=e^{e^x-1}\)

其中,\([x^n]G(x)\) 即为将 \(n\) 个整数划分为若干个集合的方案数

#include <bits/stdc++.h>
using namespace std;
#define int long long const int N=1000005; // 4 times!
const int mod=998244353,g=3; int qpow(int p,int q) {
int r = 1;
for(; q; p*=p, p%=mod, q>>=1) if(q&1) r*=p, r%=mod;
return r;
} int inv(int p) {
return qpow(p, mod-2);
} int cnt; namespace NTT {
#define pw(n) (1<<n)
const int N=1000005; // 4 times!
const int mod=998244353,g=3;
int n,m,bit,bitnum,a[N+5],b[N+5],rev[N+5];
void getrev(int l){
for(int i=0;i<pw(l);i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
}
}
int fastpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=1LL*a*a%mod){
if(b&1)ans=1LL*ans*a%mod;
}
return ans;
}
void NTT(int *s,int op){ ++cnt;
for(int i=0;i<bit;i++)if(i<rev[i])swap(s[i],s[rev[i]]);
for(int i=1;i<bit;i<<=1){
int w=fastpow(g,(mod-1)/(i<<1));
for(int p=i<<1,j=0;j<bit;j+=p){
int wk=1;
for(int k=j;k<i+j;k++,wk=1LL*wk*w%mod){
int x=s[k],y=1LL*s[k+i]*wk%mod;
s[k]=(x+y)%mod;
s[k+i]=(x-y+mod)%mod;
}
}
}
if(op==-1){
reverse(s+1,s+bit);
int inv=fastpow(bit,mod-2);
for(int i=0;i<bit;i++)a[i]=1LL*a[i]*inv%mod;
}
}
void solve(vector <int> A,vector <int> B,vector <int> &C) {
int tar=A.size()+B.size()-1;
n=A.size()-1;
m=B.size()-1;
for(int i=0;i<=n;i++) a[i]=A[i];
for(int i=0;i<=m;i++) b[i]=B[i];
m+=n;
bitnum=0;
for(bit=1;bit<=m;bit<<=1)bitnum++;
getrev(bitnum);
NTT(a,1);
NTT(b,1);
for(int i=0;i<bit;i++)a[i]=1LL*a[i]*b[i]%mod;
NTT(a,-1);
C.clear();
for(int i=0;i<=m;i++) C.push_back(a[i]);
for(int i=0;i<=min(m*2,N-1);i++) a[i]=b[i]=0;
}
} struct poly {
vector <int> a;
void cut(int n) {
while(a.size()>n) a.pop_back();
}
poly getcut(int n) {
poly A=*this;
A.cut(n);
return A;
}
void read() {
int n;
cin>>n;
for(int i=0;i<n;i++) {
int t;
cin>>t;
a.push_back(t);
}
}
void print() {
for(int i=0;i<a.size();i++) cout<<a[i]<<" ";
cout<<endl;
}
poly operator *(int b) {
poly c=*this;
for(int i=0;i<a.size();i++) (((c.a[i]*=b)%=mod)+=mod)%=mod;
return c;
}
poly operator *(const poly &b) {
poly c;
NTT::solve(a,b.a,c.a);
return c;
}
poly operator +(poly b) {
int len=max(a.size(),b.a.size());
a.resize(len);
b.a.resize(len);
poly c;
for(int i=0;i<len;i++) c.a.push_back((a[i]+b.a[i])%mod);
return c;
}
poly operator -(poly b) {
int len=max(a.size(),b.a.size());
a.resize(len);
b.a.resize(len);
poly c;
for(int i=0;i<len;i++) c.a.push_back(((a[i]-b.a[i])%mod+mod)%mod);
return c;
}
poly getinv(poly A, int n) {
A.cut(n);
poly B;
if(n==1) {
B.a.push_back(inv(A.a[0]));
}
else {
poly Bi = getinv(A,(n-1)/2+1);
B = Bi*2 - A*Bi*Bi;
B.cut(n);
}
return B;
}
poly getinv() {
int n=a.size();
poly A=*this;
return getinv(A,n);
}
poly getderi() {
poly A=*this;
poly B;
for(int i=1;i<A.a.size();i++) B.a.push_back(A.a[i]*i%mod);
return B;
}
poly getinte() {
poly A=*this;
poly B;
B.a.push_back(0);
for(int i=0;i<A.a.size();i++) B.a.push_back(A.a[i]*inv(i+1)%mod);
return B;
}
poly getln() {
poly A=*this;
int n=a.size();
return (A.getderi()*A.getinv()).getinte().getcut(2*n);
}
poly getexp(poly A,int n) {
A.cut(n);
poly ret;
ret.a.push_back(1);
if(n>1) {
poly f0=getexp(A,(n+1)/2);
ret = f0 * (ret - f0.getln() + A);
ret.cut(n);
}
return ret;
}
poly getexp() {
int len=a.size();
a.resize(a.size()*2);
return getexp(*this,a.size()).getcut(len);
}
}; int n,a[N],finv[N],frac[N]; signed main() {
ios::sync_with_stdio(false);
int m=1e5+5;
int tmp=1;
for(int i=2;i<m;i++) tmp*=i,tmp%=mod;
finv[m-1]=inv(tmp);
for(int i=m-2;i>=1;--i) finv[i]=finv[i+1]*(i+1)%mod;
frac[0]=1;
for(int i=1;i<m;i++) frac[i]=frac[i-1]*i%mod;
poly a;
a.a.push_back(0);
for(int i=1;i<m;i++) a.a.push_back(finv[i]);
poly b=a.getexp();
int t;
//cout<<cnt<<endl;
scanf("%lld",&n);
while(n--) {
scanf("%lld",&t);
printf("%lld\n",b.a[t]*frac[t]%mod);
}
}

[P5748] 集合划分计数 - 生成函数,NTT的更多相关文章

  1. LuoguP5748 集合划分计数

    题意 一个有\(n\)个元素的集合,将其分为任意个非空子集,求方案数.集合之间是无序的,\(\{\{1,2\},\{3\}\}=\{\{3\},\{1,2\}\}\). 设\(f_n\)表示用\(n\ ...

  2. 有标号DAG计数(生成函数)

    有标号DAG计数(生成函数) luogu 题解时间 首先考虑暴力,很容易得出 $ f[ i ] = \sum\limits_{ j = 1 }^{ i } ( -1 )^{ j - 1 } \bino ...

  3. bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】

    还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...

  4. P5748-集合划分计数【EGF,多项式exp】

    正题 题目链接:https://www.luogu.com.cn/problem/P5748 题目大意 求将\(n\)的排列分成若干个无序非空集合的方案. 输出答案对\(998244353\)取模. ...

  5. 2018.12.31 bzoj3992: [SDOI2015]序列统计(生成函数+ntt+快速幂)

    传送门 生成函数简单题. 题意:给出一个集合A={a1,a2,...as}A=\{a_1,a_2,...a_s\}A={a1​,a2​,...as​},所有数都在[0,m−1][0,m-1][0,m− ...

  6. CODEVS 2055 集合划分

    [题目描述] 对于从1到N(1<=N<=39)的连续整数集合,划分成两个子集合,使得每个集合的数字之和相等. 举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字 ...

  7. [CODEVS2055]集合划分

    对于从1到N(1<=N<=3)的连续整数集合,划分成两个子集合,使得每个集合的数字之和相等.举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:{3} ...

  8. HDU - 6589 Sequence (生成函数+NTT)

    题目链接 设序列a的生成函数$\large f(x)=\sum\limits_{i=0}^{n-1}a_ix^i$,则操作1,2,3分别对应将$f(x)$乘上$\Large\frac{1}{1-x}, ...

  9. 集合划分——cf1028D思维题

    非常思维的一道题目,题意很长 给定s1,s2两个集合,s1维护最大值,s2维护最小值,s1的所有元素要比s2小 操作1:往两个集合里的任意一个添加x 操作2:把x从所在的集合里删掉:要求被删的x必须是 ...

随机推荐

  1. POJ_1221_DP

    http://poj.org/problem?id=1221 简单dp,dp[i][j]表示i被划分成首位>=j的方案数. dp[i][i]为1,i为偶数时dp[i][i/2]为2. 剩下的可以 ...

  2. 《N诺机试指南》(五)进制转化

    进制转化类题目类型: 代码详解及注释解答:  //进制转化问题 #include <bits/stdc++.h> using namespace std; int main(){ // 1 ...

  3. Java 代码实现链表

    Linked List 用多少就申请多少内存. 链表是一种链式存储的线性表,所有元素的内存地址不一定连续的. 接口设计 代码实现 MyList.java(接口) package com.cyb; pu ...

  4. 题解 SP1716 【GSS3 - Can you answer these queries III】

    \[ Preface \] 没有 Preface. \[ Description \] 维护一个长度为 \(n\) 的数列 \(A\) ,需要支持以下操作: 0 x y 将 \(A_x\) 改为 \( ...

  5. Python实现IOC控制反转

    思路: 用一个字典存储beanName和资源 初始化时先将beanName和资源注册到字典中 然后用一个Dscriptor类根据beanName动态请求资源,从而实现控制反转 # -*- coding ...

  6. 《Head first设计模式》之装饰者模式

    装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 星巴兹是以扩张速度最快而闻名的咖啡连锁店.由于扩张速度太快,他们准备更新订单系统,以合乎他们的饮料供应要求. ...

  7. 校招必看硬核干货:C++怎么学才能进大厂

    目录 关于小猿 如何找资料 自我定位 岗位需求 学习路线及时间安排 资料获取方式 C++语言在历史舞台上出现了不短的时间,虽然一直面临着Python,Go等新语言的挑战,但它在基础架构和大型软件上的优 ...

  8. KubeSphere企业级分布式多租户容器管理平台

    KubeSphere企业级分布式多租户容器管理平台 KubeSphere安装部署2.1.0DEV版本

  9. MySQL热机双备之双主同步复制配置

    此配置方案来源于csdn前辈博客,奈何找不到出处了,抱拳!!! 1.  MySQL同步机制概述 MySQL支持单向.异步复制,复制过程中一台服务器充当主服务器,一台或多台服务器充当从服务器,双主同步要 ...

  10. ExecutionContext(执行上下文)综述

    >>返回<C# 并发编程> 1. 简介 2. 同步异步对比 3. 上下文的捕获和恢复 4. Flowing ExecutionContext vs Using Synchron ...