1. 程式人生 > >洛谷P3200 [HNOI2009]有趣的數列(Catalan數)

洛谷P3200 [HNOI2009]有趣的數列(Catalan數)

整數 取模 排列 right 可能 滿足 奇數 cat using

P3200 [HNOI2009]有趣的數列

題目描述

我們稱一個長度為2n的數列是有趣的,當且僅當該數列滿足以下三個條件:

(1)它是從1到2n共2n個整數的一個排列{ai};

(2)所有的奇數項滿足a1<a3<...<a2n-1,所有的偶數項滿足a2<a4<...<a2n;

(3)任意相鄰的兩項a2i-1與a2i(1<=i<=n)滿足奇數項小於偶數項,即:a2i-1<a2i。

現在的任務是:對於給定的n,請求出有多少個不同的長度為2n的有趣的數列。因為最後的答案可能很大,所以只要求輸出答案 mod P的值。

輸入輸出格式

輸入格式:

輸入文件只包含用空格隔開的兩個整數n和P。輸入數據保證,50%的數據滿足n<=1000,100%的數據滿足n<=1000000且P<=1000000000。

輸出格式:

僅含一個整數,表示不同的長度為2n的有趣的數列個數mod P的值。

輸入輸出樣例

輸入樣例#1:

3 10

輸出樣例#1:

5

對應的5個有趣的數列分別為(1,2,3,4,5,6),(1,2,3,5,4,6),(1,3,2,4,5,6),(1,3,2,5,4,6),(1,4,2,5,3,6)。

/*
    裸的卡特蘭數。。。。
    公式:C(n,2*n)/(n+1)%p
    C(n,2*n)表示在2*n個數中選n個,就是組合數啦。。。
    公式可以展開:((2*n)!/n!*(n+1)!)%p
    於是出現唯一的難點:取模
    題目中沒說p是不是質數。。。
    因為(2*n)!一定能被n!*(n+1)!)整除
    所以對於每一個小於2*n的質因數p來說,(2*n)!中一定存在數量更多的(或一樣多)的因數p
    於是可以分解質因數。。。
    這是線性的,可以預處理。。。
    於是此題解決。。。
*/ #include<iostream> #include<cstdio> #define LL long long using namespace std; LL n,p; int a[3000005],pri[3000005],cnt=0; LL pow(LL a,LL b){ LL s=1; while(b){ if(b&1) s=s*a%p; b>>=1; a=a*a%p; } return s; } int main(){ LL ans=1; LL m,s
=0; scanf("%lld%lld",&n,&p); for(int i=2;i<=n*2;i++){//歐拉篩 if(a[i]==0) pri[++cnt]=i; for(int j=1;j<=cnt&&pri[j]*i<=n*2;j++){ a[pri[j]*i]=1; if(i%pri[j]==0) break; } } for(int i=1;i<=cnt;i++){ s=0; m=2*n; while(m>0){ m=m/pri[i]; s=s+m; } m=n; while(m>0){ m=m/pri[i]; s=s-m; } m=n+1; while(m>0){ m=m/pri[i]; s=s-m; } ans=ans*pow(pri[i],s)%p; } printf("%lld\n",ans); return 0; }

洛谷P3200 [HNOI2009]有趣的數列(Catalan數)