有趣的数列

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;
}

以上是关于有趣的数列的主要内容,如果未能解决你的问题,请参考以下文章

php 有趣的代码片段在某些时候可能会有用。

PTA乙级 (1049 数列的片段和 (20分))

1049. 数列的片段和(20)

1049 数列的片段和 (20 分)

PAT 1049. 数列的片段和

「BZOJ1485」[HNOI2009] 有趣的数列 卡特兰数列