bzoj2111 Perm 排列计数

称一个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是一个质数。 数据有所加强

 

题解:题目意思比较好理解,就是问你有多少种小根堆,那么根可以确定,然后左边右边就是

组合一下,确定,如果只有一个点,那么方案数就为1,size为1,不然就是左右子树合并。

这样瞎搞。。。(⊙o⊙)…,就好了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define N 1000007
 7 #define M 1007
 8 #define ll long long
 9 using namespace std;
10 
11 int n,p;
12 ll fac[N],ni[N],f[N];
13 int siz[N];
14 
15 ll C(int n,int m)
16 {
17     if(m>n) return 0;
18     if(n<p) return fac[n]*ni[m]%p*ni[n-m]%p;
19     return C(n/p,m/p)*C(n%p,m%p)%p;
20 }
21 int main()
22 {
23     int i;
24     scanf("%d%d",&n,&p);
25     fac[0]=ni[0]=ni[1]=1;
26     
27     for(i=1;i<=n&&i<p;i++)
28         fac[i]=fac[i-1]*i%p;
29     for(i=2;i<=n&&i<p;i++)
30         ni[i]=(p-p/i)*ni[p%i]%p;
31         
32     for(i=2;i<=n&&i<p;i++)
33         (ni[i]*=ni[i-1])%=p;
34     for(i=n;i>=1;i--)
35     {
36         if(i*2+1<=n)
37         {
38             siz[i]=1+siz[i*2]+siz[i*2+1];
39             f[i]=f[i*2]*f[i*2+1]%p*C(siz[i]-1,siz[i*2])%p;
40         }
41         else if(i*2<=n)
42         {
43             f[i]=f[i*2];
44             siz[i]=1+siz[i*2];
45         }
46         else
47         {
48             f[i]=1;
49             siz[i]=1;
50         }
51     }
52     printf("%lld\n",f[1]);
53 }

 

posted @ 2017-09-24 20:45  Kaiser-  阅读(130)  评论(0编辑  收藏  举报