题目描述
我们称一个长度为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
解释:可以转换成括号匹配问题,奇数项我们看成右括号,偶数项看成左括号,每项的数x代表一个字符串中第X项放什么括号。变成很经典的问题了。直接上卡特兰数
ans=C2∗nnn+1ans=\frac{C_{2*n}^n}{n+1}ans=n+1C2∗nn,因为p不一定是质数,所以通过统计质因子来计算就好了
#include<bits/stdc++.h>
using namespace std;
const int N=2000005;
int mp[N],p[N/10],cnt[N],mod;
int pow(int a,int b){
int ans=1;
while(b){
if(b&1) ans=(long long)ans*a%mod;
a=(long long)a*a%mod;b>>=1;
}
return ans;
}
int main(){
int n;
cin>>n>>mod;
int pn=0;
for(int i=2;i<=2*n;i++){
if(!mp[i]){
p[++pn]=i;
mp[i]=i;
}
for(int j=1;j<=pn&&i*p[j]<=2*n;j++){
mp[i*p[j]]=p[j];
if(i%p[j]==0) break;
}
}
for(int i=1;i<=n;i++) cnt[i]=-1;
for(int i=n+2;i<=2*n;i++) cnt[i]=1;
for(int i=2*n;i>1;i--)
if(mp[i]<i){
cnt[mp[i]]+=cnt[i];
cnt[i/mp[i]]+=cnt[i];
}
int ans=1;
for(int i=2;i<=2*n;i++)
if(mp[i]==i)
ans=(long long)ans*pow(i,cnt[i])%mod;
cout<<ans<<endl;
return 0;
}