zhber
有好多做过的题没写下来,如果我还能记得就补吧

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("\n");}
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\n",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("\n");}
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\n",ans);
}

 

posted on 2014-12-23 20:56  zhber  阅读(951)  评论(0编辑  收藏  举报