zoukankan      html  css  js  c++  java
  • bzoj1485 [HNOI2009]有趣的数列

    1485: [HNOI2009]有趣的数列

    Time Limit: 10 Sec  Memory Limit: 64 MB

    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


    对应的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)。

    HINT

     

    Source

    Tip:

      可以先列前几项1,2,5,14,42.......

      !!!这难道不是Catalan数么?

      我们可以将奇数项看成出栈序列;

      若奇数项为1,3,4,则对应着 进(1) 出(2) 进(3) 进(4) 出(5) 出(6);

      所以方案数就为C(2n,n)/(n+1);

      求组合时用分解质数的方法;

    Code:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #define N 2000008
    using namespace std;
    
    int n,p,prime[N],pre[N],flag[N],tot,num[N];
    long long ans;
    
    inline int read(){
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+ch-48;
            ch=getchar();
        }
        return x*f;
    }
    
    void init(){
        for(int i=2;i<N;i++){
            if(!flag[i]){
                prime[++tot]=i;
                pre[i]=tot;
            }
            for(int j=1;j<=tot&&i*prime[j]<N;j++){
                flag[i*prime[j]]=1;
                pre[i*prime[j]]=j;
                if(i%prime[j]==0) break;
            }
        }
    }
    
    void add(int x,int f){
        while(x!=1){
            num[pre[x]]+=f;
            x=x/prime[pre[x]];
        }
    }
    
    int main(){
        n=read(); p=read(); tot=0;
        init();
        memset(num,0,sizeof(num));
        for(int i=n+2;i<=2*n;i++)
            add(i,1);
        for(int i=2;i<=n;i++)
            add(i,-1);
        ans=1;
        for(int i=1;i<N;i++)
            while(num[i]) ans=ans*prime[i]%p,num[i]--;
        printf("%lld",ans);
    }
  • 相关阅读:
    451. Sort Characters By Frequency
    424. Longest Repeating Character Replacement
    68. Text Justification
    44. Wildcard Matching
    160. Intersection of Two Linked Lists
    24. Swap Nodes in Pairs
    93. 递归实现组合型枚举
    98. 分形之城
    97. 约数之和
    96. 奇怪的汉诺塔
  • 原文地址:https://www.cnblogs.com/WQHui/p/8418800.html
Copyright © 2011-2022 走看看