BZOJ 2111: [ZJOI2010]Perm 排列计数 [Lucas定理]
2111: [ZJOI2010]Perm 排列计数
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 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(); }
Copyright:http://www.cnblogs.com/candy99/