2111: [ZJOI2010]Perm 排列计数 DP+组合数学
2016-02-28 15:51
330 查看
fif_i表示ii个数组成的小根堆的种类,sizeisize_i表示以ii为根的小根堆的结点个数,令i<<1,i<<1|1i<<1,i<<1|1分别表示堆的左右儿子,则有:
fi=Csizei<<1sizei−1fi<<1fi<<1|1f_i=C_{size_i-1}^{size_i<<1}f_{i<<1}f_{i<<1|1}
fi=Csizei<<1sizei−1fi<<1fi<<1|1f_i=C_{size_i-1}^{size_i<<1}f_{i<<1}f_{i<<1|1}
[code]#include<iostream> #include<cstdio> #define N 1000005 #define ll long long using namespace std; int n,P; int f[N<<1],size[N<<1],fac ,inv ; inline int read() { int a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } inline void pre() { fac[0]=fac[1]=1; inv[0]=inv[1]=1; for (int i=2;i<=n;i++) fac[i]=(ll)fac[i-1]*i%P; for (int i=2;i<=n;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P; for (int i=2;i<=n;i++) inv[i]=(ll)inv[i]*inv[i-1]%P; } inline int C(int n,int m) { if (n<m) return 0; if (n<P&&m<P) return (ll)fac *inv[m]%P*inv[n-m]%P; return C(n/P,m/P)*C(n%P,m%P)%P; } int main() { n=read(); P=read(); pre(); for (int i=n+1;i<=2*n+1;i++) f[i]=1,size[i]=0; for (int i=n;i;i--) { size[i]=size[i<<1]+size[i<<1|1]+1; f[i]=(ll)C(size[i]-1,size[i<<1])*f[i<<1]%P*f[i<<1|1]%P; } cout << f[1] << endl; return 0; }
相关文章推荐
- kidd风的IOS日志之OC中initialize方法和init方法的区别
- IOS 自动化 1-UI Automation
- 【scrapy】使用记录
- [LeetCode] Flip Game 翻转游戏
- iOS项目上线的流程
- strong 和 copy
- hdu2674-水题-大数取模-打表找规律
- Cpp_this指针与常函数
- 【scrapy】xpath
- 北京Uber优步司机奖励政策(2月28日)
- 20160228 java练习io
- Nginx 服务器安装及配置文件详解
- 算法代码实现之插入排序,Java实现
- Linux中__ASSEMBLY__ 宏定义的作用
- 4.UiCollection API 详细介绍
- LeetCode:Single Number III
- e是无理数的证明
- python 继承
- 树莓派2 ubuntu mate安装
- IOS开发日志之RunLoop的原理和使用