• 洛谷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 }
  • 相关阅读:
    c#调用系统资源大集合1
    ASP.NET GridView,DataList,Repeater日期格式显示
    msSQL存储过程中使用 IF ELSE 的规范示例
    PHP DOMDocument简单用法(XML创建、添加、删除、修改)
    PHP解析XML文档属性并编辑
    php修改和增加xml结点属性
    asp.net FileUpload控件文件格式的判断及文件大小限制
    《Linux内核设计与实现》读书笔记(四) 进程的调度
    《Linux内核设计与实现》读书笔记(七) 中断处理
    红黑树
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9540323.html
Copyright © 2020-2023  润新知