• bzoj1485 [HNOI2009]有趣的数列


    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)。
     
    这题非常蛋疼啊……
    如果固定偶数位填入的数,那么各个奇数位也是唯一确定的。因为奇数位也要递增的。
    以样例为例,偶数位有{2,4,6},{2,5,6},{3,4,6},{3,5,6},{4,5,6}这五种唯一的方案。
    除了要满足严格递增以外,还有一个条件,就是a[i]>=2i。
    这个很好yy,因为我们考虑的是偶数位的排列,前面肯定还有奇数位的数,而且大小比它小。
    前面的偶数位的数都比它小,前面奇数位的数也比它小,所以前面的数都比它小。那么它至少是2i
    问题转变为:有一个长度为n的序列,要往里头填1~2n的数,使得序列严格递增,且对于任意i,有a[i]>=2i
    这我只能想到dp:f[i][j]表示前i个位置填了,第i个位置的数大小是j的方案数。转移随便yy,最后f[n][2n]即是所求。这样n^2只有50分。代码见下
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<set>
    #include<map>
    #include<ctime>
    #define LL long long
    #define inf 0x7ffffff
    #define pa pair<int,int>
    #define pi 3.1415926535897932384626433832795028841971
    using namespace std;
    inline LL read()
    {
        LL 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*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(LL a)
    {
        if (a<0){printf("-");a=-a;}
        if (a>=10)write(a/10);
        putchar(a%10+'0');
    }
    int n,mod;
    int f[4010][4010];
    int s[4010][4010];
    inline void writeln(LL a){write(a);printf("
    ");}
    int main()
    {
        n=read();mod=read();
        for (int i=1;i<=n;i++)
            for (int j=2*i;j<=2*n;j++)
            {
                if (i!=1)f[i][j]=s[i-1][j-1]-s[i-1][2*i-3];
                else f[i][j]=1;
                f[i][j]%=mod;if (f[i][j]<0)f[i][j]+=mod;
                s[i][j]=s[i][j-1]+f[i][j];s[i][j]%=mod;if (s[i][j]<0)s[i][j]+=mod;
            }
        printf("%d
    ",f[n][2*n]);
    }

    正解竟然是……

    先把前几个打表出来,发现1,2,5,14,42……没错就是卡特兰数
    然后用公式算:h[n]=C(2n,n)/(n+1)=(2n)!/(n!(n+1)!)
    取模什么的,分解质因数搞搞
    为什么是卡特兰数?hzwer:其实就是从左往右扫每个数,把放在奇数项看作入栈,偶数看作出栈
    这TM真的是省选题!?
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<set>
    #include<map>
    #include<ctime>
    #define LL long long
    #define inf 0x7ffffff
    #define pa pair<int,int>
    #define pi 3.1415926535897932384626433832795028841971
    #
    using namespace std;
    inline LL read()
    {
        LL 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*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(LL a)
    {
        if (a<0){printf("-");a=-a;}
        if (a>=10)write(a/10);
        putchar(a%10+'0');
    }
    inline void writeln(LL a){write(a);printf("
    ");}
    int n,mod,len;
    LL ans=1;
    int prime[2000010],rep[2000010],mn[2000010];
    bool mrk[2000010];
    inline void getprime()
    {
        for(int i=2;i<=2*n;i++)
        {
            if (!mrk[i])prime[++len]=i,mn[i]=len;
            for (int j=1;prime[j]*i<=2*n&&j<=len;j++)
            {
                mrk[prime[j]*i]=1;mn[prime[j]*i]=j;
                if (i%prime[j]==0)break;
            }
        }
    }
    inline void inc(int x,int f)
    {
        while (x!=1)
        {
            rep[mn[x]]+=f;
            x/=prime[mn[x]];
        }
    }
    int main()
    {
        n=read();mod=read();
        getprime();
        for (int i=n+1;i<=2*n;i++)inc(i,1);
        for (int i=1;i<=n+1;i++)inc(i,-1);
        for (int i=1;i<=len;i++)
            while (rep[i]--)ans=(ans*prime[i])%mod;
        printf("%lld
    ",ans);
    }
    
    ——by zhber,转载请注明来源
  • 相关阅读:
    文本域光标操作(选、添、删、取)的jQuery扩展
    jQuery插件,将内容插入到光标处
    onmouseout,mouseover经过子元素也触发的问题解决方案
    【M4】非必要不提供default 构造方法
    【M3】绝对不要以多态方式处理数组
    100亿个数字找出最大的10个
    【M2】最好使用C++转型操作符
    【M26】限制某个class所能产生的对象数量
    理解extern
    变量的属性
  • 原文地址:https://www.cnblogs.com/zhber/p/4181190.html
Copyright © 2020-2023  润新知