zoukankan      html  css  js  c++  java
  • 洛谷P2606 [ZJOI2010]排列计数(数位dp)

    题目描述

    称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值

    输入输出格式

    输入格式:

    输入文件的第一行包含两个整数 n和p,含义如上所述。

    输出格式:

    输出文件中仅包含一个整数,表示计算1,2,⋯, ���的排列中, Magic排列的个数模 p的值。

    输入输出样例

    输入样例#1: 复制
    20 23 
    输出样例#1: 复制
    16
    

    说明

    100%的数据中,1 ≤N ≤ 10^6, P≤ 10^9,p是一个质数。

    题解

     数位dp?这怕不是个树位dp……

      我们把原序列看成一棵二叉树

      那么就是要我们求大小为$n$的小根堆有多少个(就是父节点比左右儿子都小)

      那么考虑dp,设$dp[i]$表示有多少个大小为$i$的小根堆,$val[i]$表示$i$的子树的大小

      因为父亲必须小于儿子,所以根节点只能是最小的点,那么剩下的$i-1$个点里有$val[l]$个可以放在左子树,剩下的都可以放在右子树,方案数为$C_{i-1}^{val[l]}$

      然后因为选不同的点之后还能有不同的方案,所以还要乘上方案数

      所以最后的状态转移方程是这样的$dp[i]=C_{i-1}^{val[l]}*dp[val[l]]*dp[val[r]]$

      然后因为要组合数取模,得用上Lucas定理

     1 //minamoto
     2 #include<cstdio>
     3 #define ll long long
     4 const int N=1e6+5;
     5 ll inv[N],fac[N],val[N],dp[N],n,mod;
     6 #define min(a,b) ((a)<(b)?(a):(b))
     7 ll qpow(ll x,ll y){
     8     ll res=1;
     9     while(y){
    10         if(y&1) res=res*x%mod;
    11         y>>=1,x=x*x%mod;
    12     }
    13     return res;
    14 }
    15 void init(){
    16     int k=min(n,mod-1);
    17     fac[0]=fac[1]=1;
    18     for(int i=2;i<=k;++i) fac[i]=fac[i-1]*i%mod;
    19 
    20     inv[k]=qpow(fac[k],mod-2);
    21     for(int i=k-1;i;--i) inv[i]=(i+1)*inv[i+1]%mod;
    22 }
    23 ll C(ll n,ll m){
    24     if(m>n) return 0;
    25     return fac[n]*inv[m]%mod*inv[n-m]%mod;
    26 }
    27 ll Lucas(ll n,ll m){
    28     if(m==0||m==n) return 1;
    29     return Lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
    30 }
    31 int main(){
    32     //freopen("testdata.in","r",stdin);
    33     scanf("%lld%lld",&n,&mod);init();
    34     for(int i=n;i;--i){
    35         val[i]=1;if((i<<1)<=n) val[i]+=val[i<<1];if((i<<1|1)<=n) val[i]+=val[i<<1|1];
    36         if((i<<1|1)<=n) dp[i]=Lucas(val[i]-1,val[i<<1])*dp[i<<1]%mod*dp[i<<1|1]%mod;
    37         else if((i<<1)<=n) dp[i]=dp[i<<1];
    38         else dp[i]=1;
    39     }
    40     printf("%lld
    ",dp[1]);
    41     return 0;
    42 }
  • 相关阅读:
    node 中的 异步地狱回调
    node 同步和异步的概念
    【Node】File System
    阅读《软技能:代码之外的生存指南》读书笔记
    整理前端学习资料以便日后查看
    【css】单选框和复选框文字垂直居中问题
    [CSS]图片与文字对齐问题--摘自张鑫旭博客
    百度首页换一换功能js实现
    个人加分项
    开课第十五周周总结
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9540323.html
Copyright © 2011-2022 走看看