zoukankan      html  css  js  c++  java
  • bzoj 2111 [ZJOI2010]Perm 排列计数(DP+lucas定理)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=2111

    【题意】

       

        给定n,问1..n的排列中有多少个可以构成小根堆。

    【思路】

        设f[i]为i个数的方案,设l为左子树大小r为右子树大小,则有:

            f[i]=C(i-1,l)*f[l]*f[r]

        因为是个堆,所以子树大小都是确定的,可以直接递推得到。

        其中C(n,m) nm比较大,可以用lucas定理求。

        模型建立的重要性可知一二。。。   

    【代码】

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 const int N = 5e6+10;
     7 
     8 int mod,n;
     9 ll f[N],fac[N],s[N];
    10 
    11 ll pow(ll a,ll p,int mod)
    12 {
    13     ll ans=1;
    14     while(p) {
    15         if(p&1) ans=(ans*a)%mod;
    16         a=(a*a)%mod; p>>=1;
    17     }
    18     return ans;
    19 }
    20 
    21 void get_pre(int n)
    22 {
    23     fac[0]=1;
    24     for(int i=1;i<=n;i++)
    25         fac[i]=(fac[i-1]*i)%mod;
    26 }
    27 ll C(ll n,ll m,int mod)
    28 {
    29     if(n<m) return 0;
    30     if(n<mod&&m<mod) {
    31         ll invn=pow(fac[n-m],mod-2,mod);
    32         ll invm=pow(fac[m],mod-2,mod);
    33         return fac[n]*invm%mod*invn%mod;
    34     }
    35     return C(n/mod,m/mod,mod)*C(n%mod,m%mod,mod)%mod;
    36 }
    37 
    38 int main()
    39 {
    40     scanf("%d%d",&n,&mod);
    41     get_pre(min(n,mod));
    42     for(int i=n;i;i--) {
    43         s[i]=s[i<<1]+s[i<<1|1]+1;
    44         f[i]=C(s[i]-1,s[i<<1],mod);
    45         if((i<<1)<=n) f[i]=(f[i]*f[i<<1])%mod;
    46         if((i<<1|1)<=n) f[i]=(f[i]*f[i<<1|1])%mod;
    47     }
    48     printf("%lld
    ",f[1]);
    49     return 0;
    50 }
  • 相关阅读:
    [BZOJ1415]聪聪和可可
    [POJ2096]Collecting Bugs
    开博第一天
    实现CSS样式垂直水平完全居中
    Vue中独立组件之间数据交互
    python Template中substitute()的使用
    eclipse 编辑 python 中文乱码的解决方案
    java Math.random()随机数的产生
    java文件读写的两种方式
    My way on Linux
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5350250.html
Copyright © 2011-2022 走看看