有趣的数列
Posted jjl0229
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有趣的数列相关的知识,希望对你有一定的参考价值。
题目连接:
https://www.acwing.com/problem/content/1318/
Description
我们称一个长度为 2n 的数列是有趣的,当且仅当该数列满足以下三个条件:
1.它是从 1 到 2n 共 2n 个整数的一个排列 ({ai});
2.所有的奇数项满足 (a_1<a_3<?<a_{2n?1}) ,所有的偶数项满足 (a_2<a_4<?<a_{2n});
3.任意相邻的两项 (a_{2i?1}) 与 (a_{2i}(1≤i≤n)) 满足奇数项小于偶数项,即:(a_{2i?1}<a_{2i})。
任务是:对于给定的 n,请求出有多少个不同的长度为 2n 的有趣的数列。
因为最后的答案可能很大,所以只要求输出答案 modP 的值。
Input
只包含用空格隔开的两个整数 n 和 P。
(1≤n≤10^6,)
(2≤P≤10^9)
Output
仅含一个整数,表示不同的长度为 2n 的有趣的数列个数 modP 的值。
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开始选数填入,把数列2n的长度模拟成n个二元组(奇,偶),满足a[奇]<a[偶],我们发现偶数选择的数,一定不能小于奇数当前选择的数。这就很符合卡特兰数01或是走方格的性质,前缀0不能少于1和y不能大于x。所以直接求卡特兰数即刻C(2n,n)-C(2n,n-1)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2000010;
typedef long long LL;
int st[N],primes[N],tot,n,p,sum[N];
void get_primes(){
for(int i=2;i<N;++i){
if(!st[i]) primes[++tot]=i;
for(int j=1;primes[j]*i<N;++j){
st[primes[j]*i]=1;
if(i%primes[j]==0) break;
}
}
}
int get(int a,int b){
int s=0;
while(a) s+=a/b,a/=b;
return s;
}
LL qmi(int a,int b){
int res=1;
while(b) {
if(b&1) res=(LL)res*a%p;
a=(LL)a*a%p;
b>>=1;
}
return res;
}
LL C(int a,int b){
for(int i=1;i<=tot;++i){
int prime=primes[i];
sum[i]=get(a,prime)-get(b,prime)-get(a-b,prime);
}
LL res=1;
for(int i=1;i<=tot;++i){
res=(res*qmi(primes[i],sum[i]))%p;
}
return res;
}
int main(){
cin>>n>>p;
get_primes();
cout<<(C(2*n,n)-C(2*n,n-1)+p)%p<<endl;
return 0;
}
以上是关于有趣的数列的主要内容,如果未能解决你的问题,请参考以下文章