• [ZJOI2010]排列计数 (组合计数/dp)


    [ZJOI2010]排列计数

    题目描述

    称一个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是一个质数。

    Solution

    组合计数+dp ... 没想到啊...

    因为这道题标签有数位dp...exm?

    好了回到这道题,看到题目中关键的一个式子

    [p_i>p_{i/2} ]

    有没有想到线段树中子节点与父节点编号的关系,其实这就是一个小根堆的限制,我们要找出所有的小根堆的个数

    可以(dp)求出来,对于一个节点i,包括它自己有(size)个节点,那么我们考虑除它自己以外(size-1)个节点中有(l)个节点可以作为左子树,剩下的作为右子树

    [dp[i]=C_{size[i]-1}^{size[l]} imes dp[l] imes dp[r] ]

    至于(size[l]怎么求?模拟dfs自下而上更新就好)

    然后,由于模数p可能<n(可能出现n%p==0,那就求不出逆元),所以要用lucas求

    Code

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define Min(a,b) (a)<(b)?(a):(b)
    #define Max(a,b) (a)>(b)?(a):(b)
    #define lol long long
    #define ll(x) (x<<1)
    #define rr(x) (x<<1|1)
    #define in(i) (i=read())
    using namespace std;
    
    const int N=1e6+10;
    
    lol read() {
    	lol ans=0,f=1; char i=getchar();
    	while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    	while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
    	return ans*=f;
    }
    
    lol n,mod;
    lol sum[N]={1},inv[N]={1},dp[N],size[N<<1];
    
    lol qpow(lol a,lol x,lol ans=1) {
        while(x) {
            if(x&1) ans=ans*a%mod;
            x>>=1,a=a*a%mod;
        }return ans;
    }
    
    void init() {
        for(lol i=1;i<=n;i++) sum[i]=sum[i-1]*i%mod;
        for(lol i=1;i<=n;i++) inv[i]=qpow(sum[i],mod-2);
    }
    
    lol C(lol n,lol m) {
        if(m>n) return 0;
        return sum[n]*inv[m]%mod*inv[n-m]%mod;
    }
    
    lol Lucas(lol n,lol m) {
        if(!m) return 1;
        return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
    }
    
    int main()
    {
        in(n),in(mod); init();
        for(int i=n;i>=1;i--) {
            size[i]=size[ll(i)]+size[rr(i)]+1;
            dp[i]=Lucas(size[i]-1,size[ll(i)])*(ll(i)>n?1:dp[ll(i)])%mod*(rr(i)>n?1:dp[rr(i)])%mod;
        }
        cout<<dp[1]<<endl;
    }
    
  • 相关阅读:
    【20210930】连岳摘抄
    【20211002】连岳摘抄
    网站首页head区代码规范(网页设计师必看)
    让你的VMware Workstation随主系统自动启动
    asp中使用图片验证码的方法
    文本筐怎样让它只能输入数字(以及怎么只能输入一个小数点和数字)
    asp通用分页函数
    系统安装秘技:精心打造WinXP万能GHOST(图)
    asp调用存储过程
    在 win2k3 下安装 webeasymail
  • 原文地址:https://www.cnblogs.com/real-l/p/9775414.html
Copyright © 2020-2023  润新知