我 们 称 一 个 长 度 为 2 n 的 数 列 是 有 趣 的 , 当 且 仅 当 该 数 列 满 足 以 下 三 个 条 件 : 我们称一个长度为 2n 的数列是有趣的,当且仅当该数列满足以下三个条件: 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件:
它 是 从 1 到 2 n 共 2 n 个 整 数 的 一 个 排 列 a i ; 它是从 1 到 2n 共 2n 个整数的一个排列 {a_i}; 它是从1到2n共2n个整数的一个排列ai;
所 有 的 奇 数 项 满 足 a 1 < a 3 < ⋯ < a 2 n − 1 , 所 有 的 偶 数 项 满 足 a 2 < a 4 < ⋯ < a 2 n ; 所有的奇数项满足 a_1
任 意 相 邻 的 两 项 a 2 i − 1 与 a 2 i ( 1 ≤ i ≤ n ) 满 足 奇 数 项 小 于 偶 数 项 , 即 : a 2 i − 1 < a 2 i 。 任意相邻的两项 a_{2i−1} 与 a_{2i }(1≤i≤n) 满足奇数项小于偶数项,即:a_{2i−1}
任 务 是 : 对 于 给 定 的 n , 请 求 出 有 多 少 个 不 同 的 长 度 为 2 n 的 有 趣 的 数 列 。 任务是:对于给定的 n,请求出有多少个不同的长度为 2n 的有趣的数列。 任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列。
因 为 最 后 的 答 案 可 能 很 大 , 所 以 只 要 求 输 出 答 案 m o d P 的 值 。 因为最后的答案可能很大,所以只要求输出答案 mod\ P 的值。 因为最后的答案可能很大,所以只要求输出答案mod P的值。
输入格式
只包含用空格隔开的两个整数 n 和 P。
输出格式
仅含一个整数,表示不同的长度为 2n 的有趣的数列个数 mod P 的值。
数据范围
1 ≤ n ≤ 1 0 6 , 2 ≤ P ≤ 1 0 9 1≤n≤10^6, 2≤P≤10^9 1≤n≤106,2≤P≤109
输入样例:
3 10
输出样例:
5
样例解释
对应的 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}。
分析:
本 题 序 列 数 量 为 2 n , n = 3 时 输 出 5 = C 6 3 − C 6 2 , 暗 示 本 题 与 卡 特 兰 数 相 关 。 本题序列数量为2n,n=3时输出5=C_{6}^{3}-C_{6}^{2},暗示本题与卡特兰数相关。 本题序列数量为2n,n=3时输出5=C63−C62,暗示本题与卡特兰数相关。
卡 特 兰 数 问 题 的 一 般 形 式 : { ① 、 递 推 式 : f ( n ) = f ( 1 ) ⋅ f ( n − 1 ) + f ( 2 ) ⋅ f ( n − 2 ) + . . . ( 求 二 叉 树 的 个 数 ) ② 、 性 质 : 任 意 前 缀 中 , A 的 数 量 ≥ B 的 数 量 。 卡特兰数问题的一般形式:\begin{cases}①、递推式:f(n)=f(1)·f(n-1)+f(2)·f(n-2)+...(求二叉树的个数)\\\\②、性质:任意前缀中,A的数量≥B的数量。\end{cases} 卡特兰数问题的一般形式:⎩⎪⎨⎪⎧①、递推式:f(n)=f(1)⋅f(n−1)+f(2)⋅f(n−2)+...(求二叉树的个数)②、性质:任意前缀中,A的数量≥B的数量。
如:组合数学 -卡特兰数 - 满足条件的01序列
题 中 要 求 0 的 个 数 ≥ 1 的 个 数 , 对 应 到 坐 标 轴 上 , 设 x 为 0 的 个 数 , y 为 1 的 个 数 , 需 满 足 x ≥ y 。 题中要求0的个数≥1的个数,对应到坐标轴上,设x为0的个数,y为1的个数,需满足x≥y。 题中要求0的个数≥1的个数,对应到坐标轴上,设x为0的个数,y为1的个数,需满足x≥y。
本题中:
我 们 需 要 确 定 哪 些 数 是 奇 数 项 , 哪 些 数 是 偶 数 项 , 再 分 别 将 奇 数 项 偶 数 项 排 序 , 就 能 够 确 定 一 种 方 案 。 我们需要确定哪些数是奇数项,哪些数是偶数项,再分别将奇数项偶数项排序,就能够确定一种方案。 我们需要确定哪些数是奇数项,哪些数是偶数项,再分别将奇数项偶数项排序,就能够确定一种方案。
现 在 从 : 1 , 2 , 3 , . . . , 2 n 中 , 从 前 到 后 依 次 确 定 每 个 数 属 于 奇 数 项 还 是 偶 数 项 , 现在从:1,2,3,...,2n中,从前到后依次确定每个数属于奇数项还是偶数项, 现在从:1,2,3,...,2n中,从前到后依次确定每个数属于奇数项还是偶数项,
我 们 需 要 保 证 , 任 意 一 种 方 案 的 前 缀 中 , 奇 数 项 的 个 数 不 能 够 小 于 偶 数 项 的 个 数 。 我们需要保证,任意一种方案的前缀中,奇数项的个数不能够小于偶数项的个数。 我们需要保证,任意一种方案的前缀中,奇数项的个数不能够小于偶数项的个数。
原因:
假 设 某 个 前 缀 的 奇 数 项 个 数 为 k 1 , 偶 数 项 个 数 为 k 2 , 且 k 1 < k 2 , 假设某个前缀的奇数项个数为k_1,偶数项个数为k_2,且k_1
k 1 < k 2 , 即 前 k 1 + k 2 个 数 中 , 偶 数 项 的 个 数 更 多 , 说 明 偶 数 项 的 最 后 一 项 之 前 , 必 有 奇 数 项 还 未 确 定 , k_1
因 为 我 们 是 从 小 到 大 选 择 各 个 位 置 上 的 数 的 , 那 么 未 确 定 的 奇 数 项 将 填 入 更 大 的 数 , 因为我们是从小到大选择各个位置上的数的,那么未确定的奇数项将填入更大的数, 因为我们是从小到大选择各个位置上的数的,那么未确定的奇数项将填入更大的数,
这 将 不 满 足 条 件 : 任 意 相 邻 的 两 项 a 2 i − 1 与 a 2 i ( 1 ≤ i ≤ n ) 满 足 奇 数 项 小 于 偶 数 项 。 这将不满足条件:任意相邻的两项 a_{2i−1} 与 a_{2i }(1≤i≤n) 满足奇数项小于偶数项。 这将不满足条件:任意相邻的两项a2i−1与a2i(1≤i≤n)满足奇数项小于偶数项。
举例:
假 设 有 2 项 奇 数 项 已 确 定 : a 1 = 1 , a 3 = 3 。 假设有2项奇数项已确定:a_1=1,a_3=3。 假设有2项奇数项已确定:a1=1,a3=3。
3 项 偶 数 项 已 确 定 : a 2 = 2 , a 4 = 4 , a 6 = 5 , 3项偶数项已确定:a_2=2,a_4=4,a_6=5, 3项偶数项已确定:a2=2,a4=4,a6=5,
那 么 a 5 的 值 必 大 于 5 , 即 a 5 > a 6 , 不 满 足 条 件 。 那么a_5的值必大于5,即a_5>a_6,不满足条件。 那么a5的值必大于5,即a5>a6,不满足条件。
因 此 , 本 题 中 的 重 要 性 质 : 因此,本题中的重要性质: 因此,本题中的重要性质:任意前缀的奇数项个数 ≥ 偶数项个数。
我 们 把 每 一 个 奇 数 项 当 作 一 个 0 , 偶 数 项 当 作 一 个 1 , 那 么 问 题 就 转 化 为 《 满 足 条 件 的 01 序 列 》 这 道 题 。 我们把每一个奇数项当作一个0,偶数项当作一个1,那么问题就转化为《满足条件的01序列》这道题。 我们把每一个奇数项当作一个0,偶数项当作一个1,那么问题就转化为《满足条件的01序列》这道题。
P 不 确 定 为 质 数 , 所 以 本 题 不 方 便 求 逆 元 , 故 用 卡 特 兰 数 差 的 形 式 来 求 解 : C 2 n n − C 2 n n − 1 。 P不确定为质数,所以本题不方便求逆元,故用卡特兰数差的形式来求解:C_{2n}^n-C_{2n}^{n-1}。 P不确定为质数,所以本题不方便求逆元,故用卡特兰数差的形式来求解:C2nn−C2nn−1。
通 过 定 义 , 分 解 阶 乘 质 因 数 + 快 速 幂 来 求 组 合 数 。 通过定义,分解阶乘质因数+快速幂来求组合数。 通过定义,分解阶乘质因数+快速幂来求组合数。
代码:
#include
#define ll long long
using namespace std;
const int N=2e6+10;
int n,mod;
int primes[N],cnt;
bool st[N];
void get_prime(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]*i<=n;j++)
{
st[primes[j]*i]=true;
if(i%primes[j]==0) break;
}
}
}
int get(int n,int p)
{
int s=0;
while(n) s+=n/p, n/=p;
return s;
}
int quick_pow(int a,int b,int mod)
{
int res=1;
while(b)
{
if(b&1) res=(ll)res*a%mod;
a=(ll)a*a%mod;
b>>=1;
}
return res;
}
int C(int n,int m)
{
int res=1;
for(int i=0;i<cnt;i++)
{
int p=primes[i];
int s=get(n,p)-get(m,p)-get(n-m,p);
res=((ll)res*quick_pow(p,s,mod))%mod;
}
return res;
}
int main()
{
cin>>n>>mod;
get_prime(2*n);
cout<<(C(2*n,n)-C(2*n,n-1)+mod)%mod<<endl;
return 0;
}