BZOJ2111: [ZJOI2010]Perm 排列計數

BZOJ2111

根據題目所給信息,要求所有2<=i<=N 時,滿足Pi>Pi/2
列一下,就是:p2>p1 ,p3>p1 ,p4>p2 ,p5>p2 ,p6>p3 ,p7>p3
發現很像一顆二叉樹!就是一顆二叉樹。。
滿足根節點小於兩個兒子節點。
然後顯然有子結構,可以dp
對於一顆以i 爲根的子樹,令l=i<<1,r=i<<1|1 ,sz[i] 表示子樹大小。
f[i]=f[l]f[r]Csz[l]sz[i]1
i 爲子樹共有sz[i] 個取值,顯然最小的要放在i 上,那麼將剩下的sz[i]1sz[l] 放在左子樹上,剩下的放在右子樹上。然後就可以愉快的dp 了。
然而p 可能大於n ,所以要用Lucas 定理。
預處理只用預處理到min(n,p1) 即可。因爲顯然這之後的用不到啊。。
當然也可以不用預處理逆元每次直接費馬小定理算,但是階乘是需要預處理的。

【代碼】

線性預處理逆元 424ms

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 1000001
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
typedef pair<int,int> pa;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,mod;
int f[N],Fac[N],sz[N],Inv[N];

int Lucas(int x,int y)
{
    if(x<y) return 0;
    if(x<mod&&y<mod) return 1LL*Fac[x]*Inv[y]%mod*Inv[x-y]%mod;
    return 1LL*Lucas(x/mod,y/mod)*Lucas(x%mod,y%mod)%mod;
}

int main()
{
    n=read(),mod=read();Fac[0]=1;f[n+1]=1;Inv[1]=Inv[0]=1;int mx=min(n+1,mod);
    for(int i=1;i<mx;i++) Fac[i]=1LL*Fac[i-1]*i%mod;
    for(int i=2;i<mx;i++) Inv[i]=1LL*(mod-mod/i)*Inv[mod%i]%mod;
    for(int i=1;i<mx;i++) Inv[i]=1LL*Inv[i]*Inv[i-1]%mod;
    for(int i=n;i;i--)
    {
        static int l,r;l=i<<1,r=i<<1|1;
        l=min(l,n+1),r=min(r,n+1);
        sz[i]=sz[l]+sz[r]+1;
        f[i]=1LL*f[l]*f[r]%mod*Lucas(sz[i]-1,sz[l])%mod;
    }
    printf("%d\n",f[1]);
    return 0;
}

不預處理直接計算逆元 2048ms

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 1000001
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
typedef pair<int,int> pa;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,mod;
int f[N],Fac[N],sz[N];

int Qpow(int x,int y)
{
    int rtn=1;
    while(y){
        if(y&1) rtn=1LL*x*rtn%mod;
        x=1LL*x*x%mod;y>>=1;
    }
    return rtn;
}

int Lucas(int x,int y)
{
    if(x<y) return 0;
    if(x<mod&&y<mod) return 1LL*Fac[x]*Qpow(1LL*Fac[y]*Fac[x-y]%mod,mod-2)%mod;
    return 1LL*Lucas(x/mod,y/mod)*Lucas(x%mod,y%mod)%mod;
}

int main()
{
    n=read(),mod=read();Fac[0]=1;f[n+1]=1;
    for(int i=1;i<N;i++) Fac[i]=1LL*Fac[i-1]*i%mod;
    for(int i=n;i;i--)
    {
        static int l,r;l=i<<1,r=i<<1|1;
        l=min(l,n+1),r=min(r,n+1);
        sz[i]=sz[l]+sz[r]+1;
        f[i]=1LL*f[l]*f[r]%mod*Lucas(sz[i]-1,sz[l])%mod;
    }
    printf("%d\n",f[1]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章