版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/83385516
正题
因为所有奇数项是升序的,所以
又因为奇数项小于偶数项
所以每个偶数位都能插在所对应奇数项的后面,换一种说法,就是把2*n个数从小到大排好序,把奇数项和偶数项丢进去,使得每一个前缀,奇数项的个数都比偶数项多。
求Catalan数有4个公式。(点链接查看)
其中有两个组合数公式是在一起的。
那么前面两种很明显不行,第一种会超时,第二种因为p不是质数,求不了逆元,而且p也没有什么很好的性质。
那么组合数,为了简单,我们选取第一种,并且化简
很明显这个东西肯定是可以整除的。
所以,又不能求逆元,那么我们就分解质因数,然后上下抵消不就行了?
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,p;
int prime[2000010],mmin[2000010];
int t[2000010];
bool vis[2000010];
long long ksm(long long x,int t){
long long tot=1;
while(t>=1){
if(t%2==1){
tot*=x;
tot%=p;
}
x*=x;
x%=p;
t/=2;
}
return tot;
}
int main(){
scanf("%d %d",&n,&p);
for(int i=2;i<=2*n;i++){
if(vis[i]==false) prime[++prime[0]]=i,mmin[i]=i;
for(int j=1;j<=prime[0] && i*prime[j]<=2*n;j++){
vis[i*prime[j]]=true;
mmin[i*prime[j]]=prime[j];
if(i%prime[j]==0) break;
}
}
int x;
for(int i=n+2;i<=2*n;i++){
x=i;
while(x!=1) t[mmin[x]]++,x/=mmin[x];
}
for(int i=2;i<=n;i++){
x=i;
while(x!=1) t[mmin[x]]--,x/=mmin[x];
}
long long ans=1;
for(int i=1;i<=prime[0];i++){
ans=ans*ksm((long long)prime[i],t[prime[i]])%p;
}
printf("%lld\n",ans);
}