3200 [HNOI2009]有趣的数列

时间:2023-03-09 09:26:57
3200 [HNOI2009]有趣的数列

题面

dalao们都说这是一题简单的卡特兰数,画一画就出来了

emmmmm……

讲讲怎么分解质因数来算组合数

先打个表

void prim(){
ex[]=ex[]=;
for(int i=;i<=*n;i++){
if(!ex[i])pri[++cnt]=i;
for(int j=;j<=cnt&&i*pri[j]<=*n;j++){
ex[i*pri[j]]=;
if(!(i%pri[j]))break;
}
}
}

卡特兰数的公式是:

h(n)=C(n,2n)/(n+1)=(2n)!/((n!)*(n+1)!) = C(n, 2n) - C(n +1, 2n)

然后就可以分解质因数了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long ll;
int n,p,cnt,pri[];
bool ex[];
int rd(){
int x=,fl=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')fl=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*fl;
}
void prim(){
ex[]=ex[]=;
for(int i=;i<=*n;i++){
if(!ex[i])pri[++cnt]=i;
for(int j=;j<=cnt&&i*pri[j]<=*n;j++){
ex[i*pri[j]]=;
if(!(i%pri[j]))break;
}
}
}
int cal (int x,int y){
int ct=;
for(ll i=x;i<=y;i*=x)
ct+=y/i;
return ct;
}
ll ksm(int x,int y){
ll cnt=;
while(y){
if(y&)cnt=cnt*x%p;
x=x*x%p;
y>>=;
}
return cnt;
}
int main(){
n=rd();p=rd();
prim();
ll ans=;
for(int i=;i<=cnt;i++){
int t=cal(pri[i],*n)-cal(pri[i],n)-cal(pri[i],n+);
ans=ans*ksm(pri[i],t)%p;
}
printf("%lld",ans);
return ;
}

emmm……当个模板记吧