zoukankan      html  css  js  c++  java
  • [BZOJ2111][ZJOI2010]Perm排列计数(组合数学)

    题意就是求一个n个点的堆的合法形态数。

    显然,给定堆中所有数的集合,则这个堆的根是确定的,而由于堆是完全二叉树,所以每个点左右子树的大小也是确定的。

    设以i为根的堆的形态数为F(i),所以F(i)+=F(sz[2*i])*F(sz[2*i+1])*C(sz[i]-1,sz[2*i])。直接DP即可。

    有个令人无语的坑,n可能大于p,要用Lucas。

    还有求阶乘逆元的时候根本不需要用快速幂算出fac[n]的逆元再逆推回去,直接跟阶乘一样顺推就好了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=1000010;
     7 int n,p,fac[N],inv[N],Fin[N],s[N],f[N];
     8 
     9 int C(int n,int m){
    10     if (n<m) return 0;
    11     if (n<p && m<p) return 1ll*fac[n]*Fin[m]%p*Fin[n-m]%p;
    12     return 1ll*C(n/p,m/p)*C(n%p,m%p)%p;
    13 }
    14 
    15 int main(){
    16     freopen("bzoj2111.in","r",stdin);
    17     freopen("bzoj2111.out","w",stdout);
    18     scanf("%d%d",&n,&p); int m=min(n,p);
    19     fac[0]=1; rep(i,1,m) fac[i]=1ll*fac[i-1]*i%p;
    20     inv[1]=1; rep(i,2,m) inv[i]=1ll*(p-p/i)*inv[p%i]%p;
    21     Fin[0]=1; rep(i,1,m) Fin[i]=1ll*Fin[i-1]*inv[i]%p;
    22     for (int i=n; i; i--){
    23         s[i]=s[i<<1]+s[(i<<1)|1]+1;
    24         f[i]=1ll*((i<<1)>n?1:f[i<<1])*((i<<1|1)>n?1:f[i<<1|1])%p*C(s[i]-1,s[i<<1])%p;
    25     }
    26     printf("%d
    ",f[1]);
    27     return 0;
    28 }
  • 相关阅读:
    topcoder srm 495 div1
    topcoder srm 500 div1
    topcoder srm 485 div1
    topcoder srm 490 div1
    IDEWorkspaceChecks.plist文件是干什么用的?
    博客推荐
    如何使用U盘安装macOS high Sierra?
    小程序--模板消息调研
    小程序--剖析小程序上传文件
    小程序--小程序开发过程中遇到的问题以及解决方案
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9285668.html
Copyright © 2011-2022 走看看