ZJOI2010 Perm 排列计数

[ZJOI2010]Perm 排列计数

时间限制: 1 Sec  内存限制: 259 MB

题目描述

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

输入

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

输出

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

样例输入

20 23 

样例输出

16 

提示

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

solution:

   建一颗二叉树(因为只用判断i和i/2的关系),直接上公式:f[size[rt]]=C(size[rt]-1,size[ls(rt)])*f[size[ls(rt)]]*f[size[rt]-1-size[ls(rt)]];,利用组合数直接可以推出来,然后利用类似树规跑一遍就好了。不过好像有线性的方法,本菜鸟不会呵呵。

    

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define ls(x) (x<<1)
 7 #define rs(x) (x<<1|1)
 8 #define root 1
 9 int n,mod,size[4*1000005];
10 long long inv[1000005],f[1000005];
11 long long qpow(long long x,int t) {
12     long long ans=1;
13     for( ; t; ans=(t&1)?(ans*x*1ll%mod):(ans),t>>=1,x=(x*x*1ll)%mod) ;
14     return ans;
15 }
16 void init() {
17     inv[0]=1;
18     for(int i=1; i<=1000000; ++i) {
19         inv[i]=(inv[i-1]*i)%mod;
20     }
21 }
22 int C(int n,int m) {
23     return inv[n]*qpow(inv[m],mod-2)%mod*qpow(inv[n-m],mod-2)%mod;
24 }
25 void dfs(int x) {
26     if(x>n) {
27         return ;
28     }
29     size[x]=1;
30     dfs(ls(x));
31     dfs((rs(x)));
32     size[x]+=size[ls(x)]+size[rs(x)];
33 }
34 void dfs2(int rt) {
35     if(rt>n) {
36         return ;
37     }
38     dfs2(ls(rt));
39     dfs2(rs(rt));
40     if(f[size[rt]]) {
41         return ;
42     }
43     if(size[rt]==1) {
44         f[0]=f[1]=1;
45         return ;
46     }
47     f[size[rt]]=C(size[rt]-1,size[ls(rt)])*f[size[ls(rt)]]%mod*f[size[rt]-1-size[ls(rt)]]%mod;
48 }
49 int main() {
50     //freopen("permzj.in","r",stdin);
51     //freopen("permzj.out","w",stdout);
52     scanf("%d%d",&n,&mod);
53     init();
54     dfs(root);
55     dfs2(root);
56     printf("%d",f[size[root]]);
57     return 0;
58 }

 

posted @ 2017-09-03 17:48  Forever_goodboy  阅读(234)  评论(0编辑  收藏  举报