题目:有趣的数列
描述
我们称一个长度为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。
輸出
仅含一个整数,表示不同的长度为2n的有趣的数列个数mod P的值
輸入範例 1
輸出範例 1
輸入範例 2
輸出範例 2
輸入範例 3
輸出範例 3
提示
对于样例1:对应的5个有趣的数列分别为
(1,2,3,4,5,6),(1,2,3,5,4,6),(1,3,2,4,5,6),(1,3,2,5,4,6),(1,4,2,5,3,6)。
50%的数据满足n≤1000 ,100%的数据满足n≤1000000且P≤1000000000。
思路
首先发现它是个卡特兰数
-
硬算前几项的数字规律(我是这样做的)
-
可以转换为一个典型的卡特兰数的例子:
n个数排成两行,使右边都大于左边,后边都大于前边,求排法数量
将奇数看成第一行,将偶数看成第二行即可。
然后发现数据很大,递推式都有除法,p也不是质数不能用逆元(虽然我也不回逆元我太弱了)
所以要用这个通项式
f(n)=n+1Cn2n
化一下
f(n)=n+1Cn2n=n!⋅n!⋅(n+1)(2n)!=n!⋅(n+1)!(2n)!
这样化的作用是可以用特殊的方法约分
枚举1~2n的所有素数
然后分别计算n,(n+1),2n中那个素数的次数(cnt1,cnt2,cnt3)
再往答案中加乘上primesi(cnt3−cnt2−cnt1)就好了
注意这里是乘不是加我就是这样错的
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
#include<bits/stdc++.h> #define LL long long using namespace std;
const LL MAXN=1000000+5;
LL n,p,cnt; bool v[MAXN]; LL primes[2*MAXN]; bool isHeshu[2*MAXN];
LL oula(LL x); LL qkpow(LL x,LL y);
int main(){
scanf("%d%d",&n,&p); oula(2*n); LL ans=1; for(LL i=1;i<=cnt;++i){ LL cnt1=0,cnt2=0,cnt3=0; LL pm=primes[i]; while(pm<=2*n){ cnt1+=n/pm; cnt2+=(n+1)/pm; cnt3+=2*n/pm; pm*=primes[i]; } LL sl=cnt3-cnt1-cnt2; ans*=qkpow(primes[i],sl); ans%=p; } printf("%lld\n",ans);
return 0; }
LL oula(LL x){ for(LL i=2;i<=x;++i){ if(!isHeshu[i]){ primes[++cnt]=i; } for(LL j=1;primes[j]*i<=x;++j){ isHeshu[primes[j]*i]=1; if(i%primes[j]==0)break; } } }
LL qkpow(LL x,LL y){ LL sum=x; LL ret=1; while(y){ if(y&1){ ret=ret*sum%p; } sum=sum*sum%p; y>>=1; } return ret; }
|