Luogu2606[ZJOI2010] 排列計數

原題鏈接:https://www.luogu.org/problemnew/show/P2606

排列計數

題目描述

稱一個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是一個質數。

題解

條件是Pi&gt;Pi/2P_i&gt;P_{i/2},反過來看就是Pi&lt;Pi&lt;&lt;1,Pi&lt;Pi&lt;&lt;11P_i&lt;P_{i&lt;&lt;1},P_i&lt;P_{i&lt;&lt;1|1},唉這不是個滿二叉小根堆嗎。

那麼問題就變成了點數爲nn的滿二叉小根堆的計數問題,dp[i]dp[i]表示以PiP_i爲根的滿二叉小根堆的個數,有轉移方程如下:
dp[i]=(siz[i]1siz[i&lt;&lt;1])×dp[i&lt;&lt;1]×dp[i&lt;&lt;11]dp[i]=\binom{siz[i]-1}{siz[i&lt;&lt;1]}\times dp[i&lt;&lt;1]\times dp[i&lt;&lt;1|1]

sizsiz數組的話在dpdp時順帶維護一下即可。

由於模數不確定,且一定爲質數,所以我們使用Lucas\mathcal{Lucas}定理:
(nm)(npmp)×(nmod&ThinSpace;&ThinSpace;pmmod&ThinSpace;&ThinSpace;p)mod&ThinSpace;&ThinSpace;p\binom{n}{m}\equiv\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\times \binom{n\mod p}{m\mod p}\mod p

代碼
#include<bits/stdc++.h>
#define ll long long
#define ls (i<<1)
#define rs (ls|1)
using namespace std;
const int M=1e6+5;
int siz[M],n,mod,mx;
ll fac[M],inv[M],dp[M];
ll power(ll x,ll p){ll r=1;for(;p;p>>=1,x=x*x%mod)if(p&1)r=r*x%mod;return r;}
ll C(int n,int m)
{
    if(m>n)return 0;
    if(n<mod&&m<mod)return fac[n]*inv[n-m]%mod*inv[m]%mod;
    return C(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
void in(){scanf("%d%d",&n,&mod);}
void ac()
{
    mx=min(mod-1,n);
    fac[0]=1;for(int i=1;i<=mx;++i)fac[i]=fac[i-1]*i%mod;
    inv[mx]=power(fac[mx],mod-2);for(int i=mx-1;i>=0;--i)inv[i]=(i+1)*inv[i+1]%mod;
    for(int i=n;i;--i)
    {
        siz[i]=1;if(ls<=n)siz[i]+=siz[ls];if(rs<=n)siz[i]+=siz[rs];
        if(rs<=n)dp[i]=C(siz[i]-1,siz[ls])*dp[ls]%mod*dp[rs]%mod;
        else if(ls<=n)dp[i]=dp[ls];
        else dp[i]=1;
    }
    printf("%lld",dp[1]);
}
int main()
{
    in(),ac();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章