洛谷P3200 [HNOI2009]有趣的數列(Catalan數)
阿新 • • 發佈:2017-08-26
整數 取模 排列 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數)