Description
我们称一个长度为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的值。
Input
输入文件只包含用空格隔开的两个整数n和P。输入数据保证,50%的数据满足n≤1000,100%的数据满足n≤1000000且P≤1000000000。
Output
仅含一个整数,表示不同的长度为2n的有趣的数列个数mod P的值。
Sample Input
3 10
Sample Output
5
HINT
对应的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)。题解
我们把奇项和偶项分别按顺序拿出来,
现在解决的问题就是将$1$~$2n$分别按顺序填入每个项中,要保证奇数项中的数的个数总不小于偶数项中的数个数。
显然就是$Catalan$数了。
对于取模...因为模数$p$不一定是质数,那么就质因数分解。
1 //It is made by Awson on 2017.10.28 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <stack> 7 #include <queue> 8 #include <vector> 9 #include <string> 10 #include <cstdio> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define Min(a, b) ((a) < (b) ? (a) : (b)) 17 #define Max(a, b) ((a) > (b) ? (a) : (b)) 18 #define Abs(x) ((x) < 0 ? (-(x)) : (x)) 19 using namespace std; 20 const int N = 1000000; 21 22 int n, pre[(N<<1)+5], prime[(N<<1)+5], tot; 23 LL p; 24 int cnt[(N<<1)+5]; 25 26 void prepare() { 27 for (int i = 2; i <= (n<<1); i++) { 28 if (!pre[i]) prime[++tot] = i; 29 for (int j = 1; j <= tot && prime[j]*i <= (n<<1); j++) { 30 pre[prime[j]*i] = prime[j]; 31 if (i%prime[j] == 0) break; 32 } 33 } 34 } 35 void work() { 36 scanf("%d%lld", &n, &p); 37 prepare(); 38 for (int i = n+2; i <= (n<<1); i++) { 39 int j = i; 40 while (pre[j]) { 41 cnt[pre[j]]++; j /= pre[j]; 42 } 43 cnt[j]++; 44 } 45 for (int i = 2; i <= n; i++) { 46 int j = i; 47 while (pre[j]) { 48 cnt[pre[j]]--; j /= pre[j]; 49 } 50 cnt[j]--; 51 } 52 LL ans = 1; 53 for (int i = 1; i <= (n<<1); i++) 54 for (int j = 1; j <= cnt[i]; j++) 55 ans = ans*i%p; 56 printf("%lld ", ans); 57 } 58 int main() { 59 work(); 60 return 0; 61 }