解题思路
因为总共是一个排列,那么确定了奇数项是哪些,偶数项就确定了。怎么判断奇数项是否合法呢,其实由于第三个限制,可以把这个数列看成一个括号序列,奇数项为((),偶数项为()),那么合法方案数自然是卡特兰数了。。模数不是质数,而且(n^2)会超时,就只能用(ans=frac{dbinom{2n}{n}}{n+1})这个式子了,化简一下就是(ans=dfrac{prodlimits_{i=n+2}^{2n}i}{prodlimits_{i=1}^ni}),然后筛一下质数,把这个式子拆成若干个素数次幂乘积形式,然后快速幂就能做了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 2000005;
typedef long long LL;
int n,MOD,cnt[MAXN],tot,prime[MAXN];
int vis[MAXN],ans=1;
inline int fast_pow(int x,int y){
int ret=1;
for(;y;y>>=1){
if(y&1) ret=(LL)ret*x%MOD;
x=(LL)x*x%MOD;
}
return ret;
}
int main(){
scanf("%d%d",&n,&MOD);vis[1]=1;
for(int i=2;i<=2*n;i++){
if(!vis[i]) vis[i]=i,prime[++tot]=i;
for(int j=1;j<=tot && (LL)i*prime[j]<=2*n;j++){
vis[i*prime[j]]=prime[j];
if(!(i%prime[j])) break;
}
}
for(int i=2;i<=n;i++) cnt[i]=-1;
for(int i=n+2;i<=n*2;i++) cnt[i]=1;
for(int i=n*2;i>1;i--) {
if(vis[i]==i) ans=((LL)ans*fast_pow(i,cnt[i])%MOD);
else cnt[vis[i]]+=cnt[i],cnt[i/vis[i]]+=cnt[i];
}
printf("%d
",ans);
return 0;
}