BZOJ 2111 [ZJOI2010]Perm 排列计数
2016-09-28 11:35
369 查看
组合数+Lucas定理
题目可以转化成求1~n排列的小根堆数目,那么对于每一个i位置,他的子树节点个数是确定的,记为f[i],那么有f[i]=C(siz[i-1],siz[i<<1])*f[i<<1]*f[i<<1|1]
注意到n可能大于p,套Lucas定理即可
【Lucas定理】注意,当且仅当p是质数时才可以用Lucas定理。在不考虑求逆元的情况下,单次时间复杂度O(logpn)
题目可以转化成求1~n排列的小根堆数目,那么对于每一个i位置,他的子树节点个数是确定的,记为f[i],那么有f[i]=C(siz[i-1],siz[i<<1])*f[i<<1]*f[i<<1|1]
注意到n可能大于p,套Lucas定理即可
【Lucas定理】注意,当且仅当p是质数时才可以用Lucas定理。在不考虑求逆元的情况下,单次时间复杂度O(logpn)
#include<cstdio> #define N 1000005 #define ll long long using namespace std; int n, p, siz[N<<1]; ll fac , inv , f[N<<1]; void init() { fac[0]=1; for(int i = 1; i <= n && i < p; i++) fac[i]=fac[i-1]*i%p; inv[1]=1; for(int i = 2; i <= n && i < p; i++) inv[i]=-(p/i)*inv[p%i]%p; inv[0]=1; for(int i = 1; i <= n && i < p; i++) inv[i]=inv[i]*inv[i-1]%p; for(int i = n; i; i--) siz[i]=siz[i<<1]+siz[i<<1|1]+1; for(int i = n+1, ii = 2*N; i < ii; i++) f[i]=1; } ll C(int m, int n) { if(m<n)return 0; if(m<=p && n<=p) { return fac[m]*inv %p*inv[m-n]%p; } else return C(m/p,n/p)*C(m%p,n%p)%p; } int main() { scanf("%d%d",&n,&p); init(); for(int i = n; i; i--) f[i]=f[i<<1]*f[i<<1|1]%p*C(siz[i]-1,siz[i<<1])%p; printf("%lld\n",(f[1]+p)%p); }
相关文章推荐
- BZOJ 2111: [ZJOI2010]Perm 排列计数 [Lucas定理]
- BZOJ2111: [ZJOI2010]Perm 排列计数
- Bzoj2111:[ZJOI2010]Perm 排列计数:树形动态规划+组合数学
- [bzoj2111][ZJOI2010]Perm 排列计数 ——问题转换,建立数学模型
- BZOJ 2111 ZJOI2010 Perm 排列计数 组合数学+Lucas定理
- BZOJ 2111 ZJOI2010 Perm 排列计数 组合数学+Lucas定理
- BZOJ 2111([ZJOI2010]Perm 排列计数-乘法逆元+完全二叉树模型+数列分数表示法)
- 【BZOJ2111】[ZJOI2010]Perm 排列计数 组合数
- 【BZOJ】2111 [ZJOI2010] Perm 排列计数
- [数学杂题]BZOJ 2111—— [ZJOI2010]Perm 排列计数
- 【bzoj2111】[ZJOI2010]Perm 排列计数 dp+Lucas定理
- BZOJ 2111: [ZJOI2010]Perm 排列计数|组合数学|Lucas定理|DP
- [BZOJ2111][ZJOI2010]Perm 排列计数 && 数学
- [BZOJ2111][ZJOI2010]Perm 排列计数(组合数学+lucas定理)
- 【BZOJ 2111】 [ZJOI2010]Perm 排列计数
- bzoj2111 [ZJOI2010]Perm 排列计数
- BZOJ 2111: [ZJOI2010]Perm 排列计数(DP+Lucas定理)
- BZOJ 2111: [ZJOI2010]Perm 排列计数 DP+lucas定理
- 【递推+lucas定理】BZOJ2111 [ZJOI2010]Perm 排列计数
- [bzoj2111][ZJOI2010]Perm 排列计数(组合数学)