[ZJOI2010]Perm 排列計數

 

 

先上題概

 

題目描述

稱一個1,2,...,N的排列P1,P2...,Pn是Magic的,當且僅當2<=i<=N時,Pi>Pi/2. 計算1,2,...N的排列中有多少是Magic的,答案可能很大,只能輸出模P之後的值html

 

輸入格式

輸入文件的第一行包含兩個整數 n和p,含義如上所述。ios

 

輸出格式

輸出文件中僅包含一個整數,表示計算1,2,?, ???的排列中, Magic排列的個數模 p的值。less

 

樣例

樣例輸入

20 23

樣例輸出

16

 

數據範圍與提示

100%的數據中,1 ≤ ??? N ≤ 106, P??? ≤ 10^9,p是一個質數。 數據有所增強ide

 
 
主要意思就是在
 
1-n的序列裏找到P(i)>P(i/2)

 

 
能夠想到二叉堆知足
 
父親比兒子優的性質
 
因此即維護小根堆從root到葉子的路知足一個magic序列
 
(1)首先是DP
 
由於兒子之間是能夠交換的
 
因此有不一樣的二叉樹
 
DP便是求二叉樹的種數
 
dp[i]=dp[i*2]*dp[i*2+1]*C(size[i]-1,size[left])

    始終沒有理解式子
    其實
    這樣一個小根堆的size,形狀都是相對肯定的
    根據乘法原理
    有兩個兒子相乘
    另外,考慮兩個兒子樹中的任意節點可交換
    所以有*C(size[i]-1,size[left])

(2)能夠看到
 
1 ≤ ??? N ≤ 106, P??? ≤ 10^9
 
這樣的數據範圍
 
須要有lucas
 
博主因實力太菜
 
實際上花了半天在調lucas
 
 
 
最後
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 #define MAXN 2000010
 5 using namespace std;
 6 int n;
 7 ll p;
 8 ll jc[MAXN];
 9 ll dp[MAXN];
10 int size[MAXN];
11 ll pow(ll a,ll b){
12     ll ans=1;
13     while(b){
14         if(b&1)ans=(ans*a)%p;
15         a=(a*a)%p;
16         b>>=1;
17     }
18     return ans%p;
19 }
20 ll C(int a,int b){
21     if(a<b)return 0;
22     if(b==0)return 1;
23     return jc[a]*pow(jc[a-b]*jc[b]%p,p-2)%p;
24 }
25 ll lucas(int a,int b){
26     if(b>a)return 0;
27     if(b==0)return 1;
28     if(a>p||b>p)return C(a%p,b%p)*lucas(a/p,b/p)%p;
29     return C(a,b)%p;
30 }
31 void dfs(ll u){
32     if(u>n){
33         dp[u]=1;
34         return ;
35     }
36     dfs(u<<1);
37     dfs(u<<1|1);
38     size[u]=size[u<<1]+size[u<<1|1]+1;
39     dp[u]=dp[u<<1]*dp[u<<1|1]%p*lucas(size[u]-1,size[u<<1])%p;
40     return ;
41 }
42 int main(){
43     scanf("%d%lld",&n,&p);
44     jc[0]=1;
45     for(int i=1;i<=n;++i)jc[i]=jc[i-1]*1ll*i%p;
46     dfs(1);
47     printf("%lld\n",dp[1]%p);
48 }
View Code

 

 
 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 #define MAXN 2000010
 5 using namespace std;
 6 int n;
 7 ll p;
 8 ll jc[MAXN];
 9 ll dp[MAXN];
10 int size[MAXN];
11 ll pow(ll a,ll b){
12     ll ans=1;
13     while(b){
14         if(b&1)ans=(ans*a)%p;
15         a=(a*a)%p;
16         b>>=1;
17     }
18     return ans%p;
19 }
20 ll C(int a,int b){
21     if(a<b)return 0;
22     if(b==0)return 1;
23     return jc[a]*pow(jc[a-b]*jc[b]%p,p-2)%p;
24 }
25 ll lucas(int a,int b){
26     if(b>a)return 0;
27     if(b==0)return 1;
28     if(a>p||b>p)return C(a%p,b%p)*lucas(a/p,b/p)%p;
29     return C(a,b)%p;
30 }
31 void dfs(ll u){
32     if(u>n){
33         dp[u]=1;
34         return ;
35     }
36     dfs(u<<1);
37     dfs(u<<1|1);
38     size[u]=size[u<<1]+size[u<<1|1]+1;
39     dp[u]=dp[u<<1]*dp[u<<1|1]%p*lucas(size[u]-1,size[u<<1])%p;
40     return ;
41 }
42 int main(){
43     scanf("%d%lld",&n,&p);
44     jc[0]=1;
45     for(int i=1;i<=n;++i)jc[i]=jc[i-1]*1ll*i%p;
46     dfs(1);
47     printf("%lld\n",dp[1]%p);
48 }
相關文章
相關標籤/搜索