zoukankan      html  css  js  c++  java
  • P3200 [HNOI2009]有趣的数列--洛谷luogu

    ---恢复内容开始---

    题目描述

    我们称一个长度为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的值。

    输入输出格式

    输入格式:

    输入文件只包含用空格隔开的两个整数n和P。输入数据保证,50%的数据满足n<=1000,100%的数据满足n<=1000000且P<=1000000000。

    输出格式:

    仅含一个整数,表示不同的长度为2n的有趣的数列个数mod P的值。

    输入输出样例

    输入样例#1: 复制
    3 10
    输出样例#1: 复制
    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)。

    -------------------------------------------------------------------------------------------------

    做之前我知道这是一道
    关于Catalan数的问题
    但是
    当我读完题目后
    我是真的蒙了
    它是怎么和Catalan数挂上关系的
    于是
    我再次被卑微了
    ————————————————————————————————————————————————————————————————————————————————————

    考察这样相邻的两项:a_{2i-1}a2i1a_{2i}a2i,根据题目的第二条原则显然有a_{2i-1}<a_{2i}a2i1<a2i

    而根据第一条原则又有奇数是递增的。

    所以有a_1<a_3<...<a_{2i-1}<a_{2i}a1<a3<...<a2i1<a2i

    这个时候可以联想到这道经典的题目

    我们可以将奇数项看为入栈,偶数项看为出栈。

    发现和入栈次数必须大于出栈次数的条件恰好相符。

    所以可以使用卡特兰数求解。

    但是直接暴力用公式是会爆的

    所以需要一些优化

    #include <bits/stdc++.h>
    using namespace std;
    long long i,j,n,m,ans,sum,x,a[2000005],b[2000005],p[2000005];
    int main()
    {
        scanf("%lld%lld",&n,&m);
    
        for (i=2; i<=2*n; i++)
        {
            if (a[i]==0) 
            {
                sum++; 
                p[sum]=i; 
                a[i]=sum;
            }//sum累加,p数组标记第sum个质数为i ,a[i]表示i这个数是由第sum个质数筛得的
        for (j=1; j<=sum; j++) //枚举当前已得到的所有质数,用这些质数筛选出在范围内的可以被这些质数筛得合数
            if (p[j]*i<=2*n) 
                a[p[j]*i]=j; 
            else 
                break; 
        //并把筛到的合数标记是被第几个质数 筛到的 
        }
    
        for (i=n+2; i<=2*n; i++)
        {
            x=i;
            while (x>1) 
            {
                b[a[x]]++; 
                x=x/p[a[x]];
            } //a[x]表示第x个数是由第a[x]个质数筛得的, 然后把表示第a[x]个质数个数的数组累加 
        //做完上述操作后将x除以已累加的质数 
        }
    
        for (i=2; i<=n; i++)
        {
            x=i;    
            while (x>1) 
            {
                b[a[x]]--; 
                x=x/p[a[x]];
            }   //重复上述操作 
        }
        ans=1;
        for (i=1; i<=sum; i++)
            for (j=1; j<=b[i]; j++) 
                ans=ans*p[i]%m; //p[i]表示第i个质数是什么,b[i]表示有第i个质数共有几个 
        printf("%lld",ans);
        return 0;   
    }
  • 相关阅读:
    Swift_Set详解
    Swift_数组详解
    Swift_字符串详解(String)
    选择排序_C语言_数组
    插入排序_C语言_数组
    快速排序_C语言_数组
    冒泡排序_C语言_数组
    七牛直播收获分享
    iOS 实用博客整理(连载版)
    iOS Swift-元组tuples(The Swift Programming Language)
  • 原文地址:https://www.cnblogs.com/darlingroot/p/10360064.html
Copyright © 2011-2022 走看看