【BZOJ】4555: [Tjoi2016&Heoi2016]求和 排列组合+多项式求逆 或 斯特林数+NTT
【题意】给定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的更多相关文章
- 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是第二类斯特林 ...
- 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是第二类斯特林 ...
- BZOJ 4555 [Tjoi2016&Heoi2016]求和 (多项式求逆)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4555 题目大意: 给定 \(S(n,m)\) 表示第二类斯特林数,定义函数 \(f(n ...
- BZOJ 4555 [Tjoi2016&Heoi2016]求和 ——分治 NTT 多项式求逆
不想多说了,看网上的题解吧,我大概说下思路. 首先考察Stirling的意义,然后求出递推式,变成卷积的形式. 然后发现贡献是一定的,我们可以分治+NTT. 也可以直接求逆(我不会啊啊啊啊啊) #in ...
- bzoj 4555 [Tjoi2016&Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化
[Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 679 Solved: 534[Submit][S ...
- 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 ...
- [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 ...
- bzoj 4555 [Tjoi2016&Heoi2016] 求和 —— 第二类斯特林数+NTT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4555 关于第二类斯特林数:https://www.cnblogs.com/Wuweizhen ...
随机推荐
- Java final用法
//继承弊端:打破了封装性. /* final关键字: 1,final是一个修饰符,可以修饰类,方法,变量. 2,final修饰的类不可以被继承. 3,final修饰的方法不可以被覆盖. 4,fina ...
- oracle和DB2的差异
1.简介 当今IT的环境正经历着剧烈的变化,依靠单一的关系型数据库管理系统(RDBMS)管理数据的公司开始逐渐减少.分析家的报告指出 ,今天超过90%的公司都拥有不只一种RDBMS.在现在紧张的经济情 ...
- 3dContactPointAnnotationTool开发日志(二六)
之前给老师看了看我的毕设,老师觉得操作太复杂了,要能像3ds max里那样可以拖动物体的轴进行平移,沿着显示的圆圈旋转以及缩放啥的.说白了就是在Unity3d的Game视图显示出Scene视图里的 ...
- IntelliJ IDEA 创建 hello world Java web Maven项目从头到尾都有图有真相2017版本
学Java的大部分吧都是要整Java web开发项目的,那么最好用的编辑器估计就是这个 IntelliJ IDEA,然后现在maven管理项目是很流行的.然后我就示范一下,如何使用这个IntelliJ ...
- 【C】树
1.子树是不相交的 2.除了根节点,每个节点有且仅有一个父节点 3.一颗n个节点的树有n-1条边 儿子兄弟表示法 满二叉树与完全二叉树 1.满二叉树是除了叶子节点,每一个节点都有两个子节点,并按顺序排 ...
- SQL SERVER SA密码忘记,windows集成身份验证都登录不了不怎么办
有时候SQL SERVER 的SA强密码策略真的很烦人,不同的系统密码策略又不一样,导致经常会忘记密码,这不,这回我本机的SQL SERVER很久不用了,彻底忘了密码是什么.查了一下资料还是找到了解决 ...
- MySQL专题3 SQL 优化
这两天去京东面试,面试官问了我一个问题,如何优化SQL 我上网查了一下资料,找到了不少方法,做一下记录 (一). 首先使用慢查询分析 通过Mysql 的Slow Query log 可以找到哪些SQ ...
- 【bzoj3064】Tyvj 1518 CPU监控 线段树维护历史最值
题目描述 给你一个序列,支持4种操作:1.查询区间最大值:2.查询区间历史最大值:3.区间加:4.区间赋值. 输入 第一行一个正整数T,表示Bob需要监视CPU的总时间. 然后第二行给出T个数表示在你 ...
- Jstack、Jmap命令简单使用
TOMCAT_ID为tomcat的进程号. 1.使用jstack查看jvm堆栈信息. /bin/ TOMCAT_ID:无法输出到单独的文件中,只能在tomcat的启动文件中打印相关的堆栈信息. jst ...
- (转)搭建本地 8.8 W 乌云漏洞库
下载地址: 开源地址: https://github.com/m0l1ce/wooyunallbugs 百度网盘: 链接: http://pan.baidu.com/s/1nvkFKox 密码: 94 ...