【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 ...
随机推荐
- ViewPager、Fragment、Matrix综合使用实现Tab滑页效果
原文地址:http://www.cnblogs.com/kross/p/3372987.html 我们实现一个上面是一个可以左右滑动的页面,下面是三个可点击切换的tab按钮,tab按钮上还有一个激活条 ...
- tooltips & click copy
tooltips & click copy shit antd & tooltips & click copy https://codesandbox.io/s/zx4wo7y ...
- delphi完美经典--第十八章
第18章数据感知组件 一.TDBText组件 用来以只读.一次一条记录的方式,显示DataSet中的某一字段值.因同样继承自TCustomLabel,TDBText组件除了数据感知功能外,与标准组件T ...
- 【linux使用】bash shell命令行常用快捷键
移动: Ctrl + A: 移动到当前编辑的命令行首, Ctrl + E: 移动到当前编辑的命令行尾, Ctrl + F 或 ->:按字符右移(往命令行尾部方向,前移) Ctrl + B 或 & ...
- adb命令模拟按键事件KeyCode
例子: //这条命令相当于按了设备的Backkey键 adb shell input keyevent 4 //可以解锁屏幕 adb shell input keyevent 82 //在屏幕上做划 ...
- p12转pem公钥私钥
cer格式证书生成p12文件,前面写了有一篇了. 这里是从p12文件导出公钥和私钥 //1.生成1.key文件 openssl pkcs12 -in apple_payment.p12 -nocert ...
- (转)java web自定义分页标签
转载至http://liuxi1024.iteye.com/blog/707784 效果如图: 1.JSP规范1.1版本后增加了自定义标签库.实现自定义标签的步骤 (1)开发自定义标签处理类. (2) ...
- P2610 [ZJOI2012]旅游
题目描述 到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~ 经过一番抉择,两人决定将T国作为他们的目的地.T国的国土可以用一个凸N边形来表示,N个顶点表示N个入境/出 ...
- 求n!中因子k的个数
思路: 求n的阶乘某个因子k的个数,如果n比较小,可以直接算出来,但是如果n很大,此时n!超出了数据的表示范围,这种直接求的方法肯定行不通.其实n!可以表示成统一的方式. n!=(km)*(m!)*a ...
- Netsh命令-修改网络IP设置
原文链接地址:https://blog.csdn.net/qq_38054198/article/details/77990914 静态设置IP 修改IP地址addr和子网掩码mask: \>n ...