BZOJ 2111: [ZJOI2010]Perm 排列计数 [Lucas定理]

2111: [ZJOI2010]Perm 排列计数

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 1936  Solved: 477
[Submit][Status][Discuss]

Description

称一个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的值。

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

该死傻逼题
 
这是个堆
模型和卡特兰数算二叉树形态数很像,只不过这个左右孩子固定了
然后算就行了,需要乘组合数
然后n>p,组合数要除阶乘,阶乘可能是p的倍数,没有逆元.....
我一开始以为不用Lucas也行,一直WA然后想了一下应该用Lucas,因为m<P的时候m!就有逆元了,剩下的系数还是用贡献的
然后改了Lucas还是一直WA....
无奈参考PoPoQQQ改了一下递推就过了.....
 
该死 我要去吃饭了
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e6+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,P;
ll fac[N];
ll Pow(ll a,int b,int P){
    ll re=1;
    for(;b;b>>=1,a=a*a%P)
        if(b&1) re=re*a%P;
    return re;
}
void iniFac(int n){
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
}
ll C(int n,int m){
    return fac[n]*Pow(fac[m]*fac[n-m]%P,P-2,P)%P;
}
ll Lucas(int n,int m){
    if(n<m) return 0;
    ll re=1;
    for(;m;m/=P,n/=P) re=re*C(n%P,m%P)%P;
    return re;
}
int size[N<<1];
ll f[N<<1];
void dp(){
    for(int i=n;i>=1;i--){
        int l=i<<1,r=i<<1|1;
        size[i]=size[l]+size[r]+1;
        f[i]=Lucas(size[i]-1,size[l])*(l>n?1:f[l])%P*(r>n?1:f[r])%P;
    }
    printf("%lld",f[1]);
}
int main(){
    freopen("in","r",stdin);
    n=read();P=read();
    iniFac(n);
    dp();
}

 

 
 
posted @ 2017-02-16 12:48  Candy?  阅读(332)  评论(0编辑  收藏  举报