BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]
4555: [Tjoi2016&Heoi2016]求和
题意:求$$
\sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \
S是第二类斯特林数
***
首先你要把这个组合计数肝出来,~~于是我去翻了一波《组合数学》~~
*用斯特林数容斥原理推导那个式子可以直接出卷积形式,见下一篇,本篇是分治fft做法*
</br>
###组合计数
**斯特林数** $S(n,i)$表示将n个不同元素划分成i个相同集合非空的方案数
**Bell数** $B(n)=\sum\limits_{i=0}^n S(n,i)$也就是分成任意个相同的集合
有一个递推式
\]
B(n) = \sum_{i=0}^{n-1} \binom{n-1}{n-1-i}B(i) = \sum_{i=0}^{n-1} \binom{n-1}{i}B(i)
考虑和第一个元素在同一个集合的元素有几个,剩下的是子问题
或者这么想,因为每个集合相同,我们规定第一个元素在一个集合后这个集合就不相同了,剩下的元素分入这个不相同的集合或者成为子问题
</br>
$S'(n,i)=S(n,i)*i!$就是**集合不相同**啦,
\]
B'(n) = \sum_{i=1}^n \binom{n}{i}B'(n-i)
因为每个集合都不相同,我们没有必要规定第一个元素在集合里了,直接枚举第一个集合元素个数就可以了
</br>
然后那个$2^j$可以认为每个集合有两种颜色,枚举当前集合顺便枚举颜色,乘上一个2就行了
令$f(n)=2 \sum\limits_{i=1}^n \binom{n}{i} f(n-i)$,答案就是$\sum_{i=0}^n f(i)$
快速求出f就可以做了,整理一下发现
\]
f(n) = 2 n! \sum_{i=1}^n \frac{1}{i!} \frac{f(n-i)}{(n-i)!}
</br>
###分治fft
和CDQ分治一样,每次用$[l,mid]$更新$[mid+1,r]$
可以发现,$f(i)[mid+1,r]$都是$\frac{f(i)}{i!}[l,mid]$卷上$\frac{1}{i!}[1,r-l]$的结果
我们把两个函数$[l,mid]$和$[1,r-l]$的部分拿出来做卷积,更新$[mid+1,r]$
可以认为先把向量移动了l位
复杂度$O(nlog^2n)$,13560ms,~~貌似别人的分治fft更慢20000ms多~~
</br>
注意初始值$f[0]=1$因为$S(0,0)=1$,以及cdq(0,n)
</br>
###多项式求逆
当然也可以,具体看[51nod这篇讨论](http://www.51nod.com/question/index.html#!questionId=1713)吧
把$f_0 x^0$单独拿出来的思想比较有意思,$A(x)$从0开始,$B(x)$从1开始($B_0 = 0$)
$$A(x) = F_0 x^0 + A(x) B(x)\]
update 2017.5.3 : 发现tls貌似补了一句\(2x e^x\),求这个东西来做也可以,但不如直接处理处B来方便
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=(1<<18)+5, INF=1e9;
const ll P=998244353, g=3;
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
ll Pow(ll a, ll b) {
ll ans=1;
for(; b; b>>=1, a=a*a%P)
if(b&1) ans=ans*a%P;
return ans;
}
int n, rev[N];
ll inv[N], fac[N], facInv[N];
ll f[N], a[N], b[N];
void dft(ll *a, int n, int flag) {
for(int i=0; i<n; i++) if(i<rev[i]) swap(a[i], a[rev[i]]);
for(int l=2; l<=n; l<<=1) {
int m=l>>1;
ll wn = Pow(g, flag==1 ? (P-1)/l : P-1-(P-1)/l);
for(ll *p=a; p!=a+n; p+=l) {
ll w=1;
for(int k=0; k<m; k++) {
ll t = w*p[k+m];
p[k+m]=(p[k]-t+P)%P;
p[k]=(p[k]+t)%P;
w=w*wn%P;
}
}
}
if(flag==-1) {
ll inv=Pow(n, P-2);
for(int i=0; i<n; i++) a[i]=a[i]*inv%P;
}
}
void cdq(int l, int r) {
if(l==r) return;
int mid=(l+r)>>1;
cdq(l, mid);
int lim=r-l+1, n=1, k=0;
while(n<lim) n<<=1, k++;
for(int i=0; i<n; i++) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
for(int i=0; i<n; i++) a[i]=b[i]=0;
for(int i=l; i<=mid; i++) a[i-l] = f[i];
for(int i=0; i<=r-l; i++) b[i] = facInv[i];
dft(a, n, 1); dft(b, n, 1);
for(int i=0; i<n; i++) a[i]=a[i]*b[i]%P;
dft(a, n, -1);
for(int i=mid+1; i<=r; i++) f[i]=(f[i] + 2*a[i-l])%P;
cdq(mid+1, r);
}
int main() {
freopen("in","r",stdin);
n=read();
inv[1]=1; fac[0]=facInv[0]=1;
for(int i=1; i<=n; i++) {
if(i!=1) inv[i] = (P-P/i)*inv[P%i]%P;
fac[i] = fac[i-1]*i%P;
facInv[i] = facInv[i-1]*inv[i]%P;
}
f[0]=1;
cdq(0, n);
ll ans=0;
for(int i=0; i<=n; i++) ans = (ans + f[i]*fac[i]%P)%P;
if(ans<0) ans+=P;
printf("%lld\n", ans);
}
BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]的更多相关文章
- BZOJ 4555 [Tjoi2016&Heoi2016]求和 ——分治 NTT 多项式求逆
不想多说了,看网上的题解吧,我大概说下思路. 首先考察Stirling的意义,然后求出递推式,变成卷积的形式. 然后发现贡献是一定的,我们可以分治+NTT. 也可以直接求逆(我不会啊啊啊啊啊) #in ...
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]
4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...
- [BZOJ4555][TJOI2016&HEOI2016]求和(分治FFT)
4555: [Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 525 Solved: 418[Sub ...
- bzoj 4555 [Tjoi2016&Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化
[Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 679 Solved: 534[Submit][S ...
- BZOJ 4555 [Tjoi2016&Heoi2016]求和 (多项式求逆)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4555 题目大意: 给定 \(S(n,m)\) 表示第二类斯特林数,定义函数 \(f(n ...
- bzoj 4555: [Tjoi2016&Heoi2016]求和【NTT】
暴力推式子推诚卷积形式,但是看好多blog说多项式求逆不知道是啥.. \[ \sum_{i=0}^{n}\sum_{j=0}^{n}S(i,j)*2^j*j! \] \[ S(i,j)=\frac{1 ...
- 洛谷P4721 【模板】分治 FFT(生成函数+多项式求逆)
传送门 我是用多项式求逆做的因为分治FFT看不懂…… upd:分治FFT的看这里 话说这个万恶的生成函数到底是什么东西…… 我们令$F(x)=\sum_{i=0}^\infty f_ix^i,G(x) ...
- [BZOJ 4555][Tjoi2016&Heoi2016]求和
题意 给定 $n$ , 求下式的值: $$ f(n)= \sum_{i=0}^n\sum_{j=0}^i\begin{Bmatrix}i\\ j\end{Bmatrix}\times 2^j\time ...
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 (NTT + 第二类斯特林数)
题意 给你一个数 \(n\) 求这样一个函数的值 : \[\displaystyle f(n)=\sum_{i=0}^{n}\sum_{j=0}^{i} \begin{Bmatrix} i \\ j ...
随机推荐
- javascript 之原型、原型链-14
原型 原型是一个对象,每个函数对象(在javascript 之对象中说过函数也是对象 )都有一个属性(prototype)指向这个对象--原型对象,这个对象的作用是让所有对象实例共享原型对象中的属性. ...
- oracle 数据库——知识点总结(加示例)
新入oracle数据库,把目前学到的知识点记录下来,可能都比较基础,但还是比较全的,里面的示例都是自己在PL/SQL中跑过的,如果有错误,还望各位大侠指出哈. 创建用户 1.创建用户(使用管理员身份创 ...
- 初窥React Native
这两天在学习react native,被虐得布耀布耀的,运行一个hello world花了一天时间(手动捂脸). 由于是跟着官网走,所以一开始便是开发环境的搭建.其他的就不说了(详情见 React N ...
- Java排序算法分析与实现:快排、冒泡排序、选择排序、插入排序、归并排序(二)
一.概述: 上篇博客介绍了常见简单算法:冒泡排序.选择排序和插入排序.本文介绍高级排序算法:快速排序和归并排序.在开始介绍算法之前,首先介绍高级算法所需要的基础知识:划分.递归,并顺带介绍二分查找算法 ...
- 01 mysql的安装(windows)
在安装mysql之前,一般是先下载mysql,推荐大家去Oracle的官网下载,而且尽量使用免安装的版本(即压缩版,解压之后就可以使用的版本,不是.exe的安装版本),因为安装版的mysql在安装过程 ...
- Redis在Php项目中的实际应用场景
前言 一些案例中有的同学说为什么不可以用string类型,string类型完全可以实现呀 我建议你看下我的专栏文章<Redis高级用法>,里面介绍了用hash类型的好处 商品维度计数 对商 ...
- DEDE中如何过滤掉Html标签,并且截取字符串长度
在dede标签中只要使用2个函数就可以. [field:body function="cn_substr(Html2text(@me),80)"/] Html2text()函数是去 ...
- 求助帖:android开发初期:为什么我在活动二设置的singInstance模式跑到活动三去了???
求android开发的高手帮我看看这个问题吧: <activity android:name=".SecondActivity" android:label="Th ...
- MySQL时间差返回月个数
select PERIOD_DIFF(date_format(now(),'%Y%m'),date_format('2010-11-30','%Y%m')) 1. MySQL 为日期增加一个时间间隔: ...
- Hadoop问题:chmod 0700 of directory /var/lib/apt/lists/
问题描述: apt-get update W: chmod of directory /: Operation not permitted) E: Could not open : Permissio ...