Perm 排列计数(bzoj 2111)

Description

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

Input

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

Output

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

Sample Input

20 23

Sample Output

16

HINT

100%的数据中,1 ≤ ��� N ≤ 106, P��� ≤ 10^9,p是一个质数。 数据有所加强

/*
    求n个数组成小根堆的方案数。 
    设f[i]为以i为根的小根堆方案数。
    f[i]=C(sz[i]-1,sz[i*2])*f[i*2]*f[i*2+1]。 
    最神奇的是被lucas坑了一把,当n>mod时预处理就成0啦!!! 
*/
#include<iostream>
#include<cstdio>
#define N 1000010
#define lon long long
using namespace std;
int n,mod,hal[N],sz[N];
lon inv[N],jc1[N],jc2[N];
void init(){
    inv[0]=inv[1]=1;for(int i=2;i<=n;i++) inv[i]=((mod-mod/i)*inv[mod%i])%mod;
    jc1[0]=1;for(int i=1;i<=n;i++) jc1[i]=(jc1[i-1]*i)%mod;
    jc2[0]=1;for(int i=1;i<=n;i++) jc2[i]=(jc2[i-1]*inv[i])%mod;
}
lon C(int n,int m){
    if(n<m) return 0;
    if(n>mod||m>mod) return (C(n%mod,m%mod)*C(n/mod,m/mod))%mod;
    else return ((jc1[n]*jc2[m])%mod*jc2[n-m])%mod;
}
void dfs1(int x){
    sz[x]=1;
    if(x*2<=n) dfs1(x*2),sz[x]+=sz[x*2];
    if(x*2+1<=n) dfs1(x*2+1),sz[x]+=sz[x*2+1];
}
lon dfs2(int x){
    if(x*2>n) return 1;
    lon tot=C(sz[x]-1,sz[x*2]);
    if(x*2<=n) tot=(tot*dfs2(x*2))%mod;
    if(x*2+1<=n) tot=(tot*dfs2(x*2+1))%mod;
    return tot;
}
int main(){
    scanf("%d%d",&n,&mod);
    init();
    dfs1(1);
    printf("%d",dfs2(1));
    return 0;
}

 

posted @ 2017-04-06 22:21  karles~  阅读(401)  评论(0编辑  收藏  举报