【题意】给定n,求Σi=0~nΣj=1~i s(i,j)*2^j*j!,n<=10^5。

【算法】生成函数+排列组合+多项式求逆

【题解】参考: [BZOJ4555][Tjoi2016&Heoi2016]求和-NTT-多项式求逆

$ans=\sum_{i=0}^{n}\sum_{j=0}^{i}s(i,j)*2^j*j!$

令$g(n)=\sum_{j=0}^{n}s(n,j)*2^j*j!$

则ans是Σg(i),只要计算出g(i)的生成函数就可以统计答案。

g(n)可以理解为将n个数划分成若干集合,每个集合有2个属性的排列数。基于此实际意义,通过枚举第一个集合来递推g(n)。

$g(n)=\sum_{i=1}^{n}2*C(n,i)*g(n-i)$

特别的,g(0)=1

两边乘n!(令人窒息的操作),得

$\frac{g(n)}{n!}=\sum_{i=1}^{n}\frac{2}{i!}*\frac{g(n-i)}{(n-i)!}$

这已经是卷积的形式了:

$F(n)=\sum_{i=1}^{n}\frac{2}{n!}*x^i$

$G(n)=\sum_{i=0}^{n}\frac{g(n)}{n!}*x^i$

注意此时F*G卷积后,G(0)的位置是0,所以

$G(n)=F(n)G(n)+1$

移项得,

$G(n)=\frac{1}{1-F(n)}$

最后,多项式求逆即可,复杂度O(n log n)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=,MOD=;
void gcd(int a,int b,int &x,int &y){
if(!b){x=;y=;}else{gcd(b,a%b,y,x);y-=x*(a/b);}
}
int inv(int a){int x,y;gcd(a,MOD,x,y);return (x%MOD+MOD)%MOD;}
int power(int x,int k){
int ans=;
while(k){
if(k&)ans=1ll*ans*x%MOD;
x=1ll*x*x%MOD;
k>>=;
}
return ans;
}
namespace ntt{
int o[maxn],oi[maxn],f[maxn];
void init(int n){
int x=,p=power(,(MOD-)/n);
for(int k=;k<n;k++){
o[k]=x;oi[k]=inv(o[k]);
x=1ll*x*p%MOD;
}
}
void transform(int *a,int n,int *o){
int k=;
while((<<k)<n)k++;
for(int i=;i<n;i++){
int t=;
for(int j=;j<k;j++)if((<<j)&i)t|=(<<(k-j-));
if(i<t)swap(a[i],a[t]);
}
for(int l=;l<=n;l*=){
int m=l>>;
for(int *p=a;p!=a+n;p+=l){
for(int i=;i<m;i++){
int t=1ll*p[i+m]*o[n/l*i]%MOD;
p[i+m]=(p[i]-t+MOD)%MOD;
p[i]=(p[i]+t)%MOD;
}
}
}
}
void dft(int *a,int n){transform(a,n,o);}
void idft(int *a,int n){
transform(a,n,oi);int v=inv(n);
for(int i=;i<n;i++)a[i]=1ll*a[i]*v%MOD;
}
void pinv(int *F,int *g,int n){
if(n==){g[]=inv(F[]);return;}
pinv(F,g,n>>);n<<=;
init(n);//
for(int i=;i<n/;i++)f[i]=F[i],f[i+n/]=;
dft(f,n);dft(g,n);
for(int i=;i<n;i++)g[i]=1ll*g[i]*(-1ll*f[i]*g[i]%MOD+MOD)%MOD;//1ll
idft(g,n);for(int i=n/;i<n;i++)g[i]=;// }
}
int F[maxn],G[maxn],n,fac[maxn];
int main(){
int n,N=;
scanf("%d",&n);n++;
while(N<n)N*=;
fac[]=;
for(int i=;i<n;i++)fac[i]=1ll*fac[i-]*i%MOD;
for(int i=;i<n;i++)F[i]=((-*inv(fac[i]))%MOD+MOD)%MOD;
F[]++;
ntt::pinv(F,G,N);
int ans=;
for(int i=;i<n;i++)ans=(ans+1ll*G[i]*fac[i]%MOD)%MOD;
printf("%d",ans);
return ;
}

注意:多项式求逆过程中每次都要对不同的n进行一次预处理omega[]。

另一种做法

【算法】斯特林数+NTT

【题解】首先有第二类斯特林数的通项公式。

$s(n,m)=\frac{1}{m!}\sum_{k=0}^{m}(-1)^k*C(m,k)*(m-k)^n$

当斯特林数s(n,m)满足m>n时,上述公式计算结果为0,所以第二个Σ可以扩展到n。

$ans=\sum_{i=0}^{n}\sum_{j=0}^{n}s(i,j)*s^j*j!$

代入第二类斯特林数公式。

$ans=\sum_{i=0}^{n}\sum_{j=0}^{n}2^j*j!*\frac{1}{j!}\sum_{k=0}^{j}(-1)^k*\frac{j!}{k!(j-k)!}*(j-k)^i$

通过组合数的分解,向卷积靠拢。

注意到Σi只对最后一个括号有影响,所以移动到最后。

$ans=\sum_{j=0}^{n}2^j*j!\sum_{k=0}^{j}\frac{(-1)^k}{k!}*\frac{\sum_{i=0}^{n}(j-k)^i}{(j-k)!}$

这已经是标准的卷积形式(第二个函数分子是等比数列可以直接计算)。

使用NTT计算。

注意:

1.n=0,只有使0^0=1,斯特林数通项公式才能处理s(0,0)的情况。

2.n=1,等比数列求和公式不能处理Σ1^i即q=1的情况。

所以特殊地,g[0]=1,g[1]=n+1。先计算完再n++。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=,MOD=; int power(int x,int k){
int ans=;
while(k){
if(k&)ans=1ll*ans*x%MOD;
x=1ll*x*x%MOD;
k>>=;
}
return ans;
}
int inv(int x){return power(x,MOD-);}
namespace ntt{
int o[maxn],oi[maxn];
void init(int n){
int x=,g=power(,(MOD-)/n);
for(int k=;k<n;k++){
o[k]=x;oi[k]=inv(o[k]);
x=1ll*x*g%MOD;
}
}
void transform(int *a,int n,int *o){
int k=;
while((<<k)<n)k++;
for(int i=;i<n;i++){
int t=;
for(int j=;j<k;j++)if((<<j)&i)t|=(<<(k-j-));
if(i<t)swap(a[i],a[t]);
}
for(int l=;l<=n;l*=){
int m=l>>;
for(int *p=a;p!=a+n;p+=l){
for(int i=;i<m;i++){
int t=1ll*p[i+m]*o[n/l*i]%MOD;
p[i+m]=(p[i]-t+MOD)%MOD;
p[i]=(p[i]+t)%MOD;
}
}
}
}
void dft(int *a,int n){transform(a,n,o);}
void idft(int *a,int n){
transform(a,n,oi);
int x=inv(n);
for(int i=;i<n;i++)a[i]=1ll*a[i]*x%MOD;
}
}
int n,fac[maxn],f[maxn],g[maxn];
int main(){
scanf("%d",&n);
fac[]=;
for(int i=;i<=n;i++)fac[i]=1ll*fac[i-]*i%MOD;
for(int i=;i<=n;i++)f[i]=1ll*((i&)?MOD-:)*inv(fac[i])%MOD;
for(int i=;i<=n;i++)g[i]=1ll*(-power(i,n+)+MOD)*inv((-i+MOD)%MOD)%MOD*inv(fac[i])%MOD;
g[]=;g[]=n+;//
n++;int N=;//
while(N<n+n)N*=;
ntt::init(N);
ntt::dft(f,N);ntt::dft(g,N);
for(int i=;i<N;i++)f[i]=1ll*f[i]*g[i]%MOD;
ntt::idft(f,N);
int ans=;
for(int i=;i<n;i++)ans=(ans+1ll*power(,i)*fac[i]%MOD*f[i]%MOD)%MOD;
printf("%d",ans);
return ;
}

【BZOJ】4555: [Tjoi2016&Heoi2016]求和 排列组合+多项式求逆 或 斯特林数+NTT的更多相关文章

  1. 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是第二类斯特林 ...

  2. 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是第二类斯特林 ...

  3. BZOJ 4555 [Tjoi2016&Heoi2016]求和 (多项式求逆)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4555 题目大意: 给定 \(S(n,m)\) 表示第二类斯特林数,定义函数 \(f(n ...

  4. BZOJ 4555 [Tjoi2016&Heoi2016]求和 ——分治 NTT 多项式求逆

    不想多说了,看网上的题解吧,我大概说下思路. 首先考察Stirling的意义,然后求出递推式,变成卷积的形式. 然后发现贡献是一定的,我们可以分治+NTT. 也可以直接求逆(我不会啊啊啊啊啊) #in ...

  5. bzoj 4555 [Tjoi2016&Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化

    [Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 679  Solved: 534[Submit][S ...

  6. 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 ...

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

  8. BZOJ 4555: [Tjoi2016&Heoi2016]求和 (NTT + 第二类斯特林数)

    题意 给你一个数 \(n\) 求这样一个函数的值 : \[\displaystyle f(n)=\sum_{i=0}^{n}\sum_{j=0}^{i} \begin{Bmatrix} i \\ j ...

  9. bzoj 4555 [Tjoi2016&Heoi2016] 求和 —— 第二类斯特林数+NTT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4555 关于第二类斯特林数:https://www.cnblogs.com/Wuweizhen ...

随机推荐

  1. 解决因生成javadoc失败导致Maven打包失败问题

    方案就是设置javadoc生成失败时不导致整个打包失败: <plugin> <groupId>org.apache.maven.plugins</groupId> ...

  2. C语言文法阅读与理解序

    <指针>→*  | * < 指针> <直接声明符>  <标识符> | <直接声明>[]| <直接声明>[常量表达式] | < ...

  3. 201621123037 《Java程序设计》第14周学习总结

    作业14-数据库 标签(空格分隔): Java 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 使用数据库技术改造你的系统 2.1 简述如何使用数据库技术改造 ...

  4. 阿里中间件RocketMQ

    阿里RocketMQ是怎样孵化成Apache顶级项目的? RocketMQ 迈入50万TPS消息俱乐部 Apache RocketMQ背后的设计思路与最佳实践 专访RocketMQ联合创始人:项目思路 ...

  5. 【bzoj3992】[SDOI2015]序列统计 原根+NTT

    题目描述 求长度为 $n$ 的序列,每个数都是 $|S|$ 中的某一个,所有数的乘积模 $m$ 等于 $x$ 的序列数目模1004535809的值. 输入 一行,四个整数,N.M.x.|S|,其中|S ...

  6. 【bzoj4027】[HEOI2015]兔子与樱花 树形dp+贪心

    题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...

  7. C++解析(3):布尔类型与三目运算符

    0.目录 1.布尔类型 2.三目运算符 3.小结 1.布尔类型 C++中的布尔类型: C++在C语言的基本类型系统之上增加了bool C++中的bool可取的值只有true和false 理论上bool ...

  8. 【BZOJ3242】【NOI2013】快餐店(动态规划)

    [BZOJ3242][NOI2013]快餐店(动态规划) 题面 BZOJ 题解 假设我们要做的是一棵树,那么答案显然是树的直径的一半. 证明? 假设树的直径是\(2d\),那么此时最远点的距离是\(d ...

  9. BZOJ5315 [JSOI2018]防御网络 【仙人掌 + dp】

    题目链接 BZOJ5315 题解 题目好吓人= =点仙人掌 + 斯坦纳树 我们只需求出对于所有选点的方案的斯坦纳树边长总和 \(n\)那么大当然不能状压,但是考虑一下如果这是一棵树,一个方案的贡献就是 ...

  10. bzoj1907: 树的路径覆盖(树形DP)

    一眼题... f[i][0]表示在i连接一个子树的最小值,f[i][1]表示在i连接两个子树的最小值,随便转移... 样例挺强的1A了美滋滋... UPD:学习了2314的写法之后短了好多T T #i ...