题目描述
我们称一个长度为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:
5
虽然好多人是打表找规律发现答案是卡特兰数的2333,但其实你如果学了杨表就会发现这就是一个2*n的杨表,直接列式子就是 (2n)!/(n+1)!/n!。
但是模数不是质数怎么办啊QWQ
一开始想要把P质因数分解然后用二元组表示阶乘最后CRT合并的,而且竟然质因数分解也想写最近新学的Pillard's Rho,这么一算代码至少要5k啊。。。写死算了QWQ
但是想一想,模数不是质数最多也就是做除法比较麻烦。。。那我们干脆就不做除法了,直接把每个质因子在答案里的次数算出来然后都乘起来不就行了吗QWQ
因为只需要算三个阶乘,所以上述方法还是贼快并且贼好写的233333
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2000005;
inline int ksm(int x,int y,const int ha){
int an=1;
for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
return an;
}
int n,p,zs[maxn/10],t=0,ans=1,N;
bool v[maxn];
inline int solve(int x){
int now=0;
ll y=x;
while(y<=N) now+=N/y-n/y-(n+1)/y,y*=(ll)x;
return ksm(x,now,p);
}
int main(){
scanf("%d%d",&n,&p),N=n<<1;
const int ha=p;
for(int i=2;i<=N;i++){
if(!v[i]) zs[++t]=i,ans=ans*(ll)solve(i)%ha;
for(int j=1,u;j<=t&&(u=zs[j]*i)<=N;j++){
v[u]=1;
if(!(i%zs[j])) break;
}
}
printf("%d\n",ans);
return 0;
}