BZOJ 1485 [HNOI2009]有趣的数列 - 卡特兰数

关于卡特兰数的介绍
->http://blog.csdn.net/hackbuteer1/article/details/7450250
(其中第一道题就是这道题的翻版)

首先将2n个数排列为序列A,从前向后选出n个作为奇数项,剩下的作为偶数项,而且选定的数组成的有趣的数列只能有一种(选出的奇数项数字和偶数项数字要升序插入数列,排列只有一种)。要保证奇数项小于偶数项,那么对于每一位A中的数,其前选出的奇数项的个数必然要大于等于偶数项的个数。把它转化成了经典的进出栈问题。

对于进出栈问题也复习一下:设n个数进出站的总数为h(n),设最后时刻出站的元素为i,那么比i先进栈且先出栈的种类数为:h(i-1),比i后进栈且先出栈的种数为:h(n-i+1),而i的取值范围为1~n,于是有h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)h(0)

首先打了个递推式的写法,复杂度O(n2)
然后直接用卡特兰数的组合数公式,分解一下质因数会达到O(nlogn)。

h(n)=Cn2nn+1=Cn2nCn12n

(50分)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>

using namespace std;

int n,mod;
int dp[1000005];

int main()
{
    scanf("%d%d",&n,&mod);
    dp[0]=dp[1]=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=0;j<=i-1;j++)
            dp[i]=(dp[i]+1LL*dp[j]%mod*dp[i-j-1]%mod)%mod;
    }
    cout<<dp[n];
    return 0;
}

(100分)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>

using namespace std;

const int maxn=2000005;

int n,mod,cnt;
int prime[maxn],num[maxn],fa[maxn][2];
bool is[maxn];

void linear_shaker()
{
    for(int i=2;i<maxn;i++)
    {
        if(!is[i])
        {
            prime[++cnt]=i;
            fa[i][0]=i;
            fa[i][1]=1;
        }
        int t;
        for(int j=1;j<=cnt&&(t=prime[j]*i)<maxn;j++)
        {
            is[t]=true;
            fa[t][0]=prime[j];
            fa[t][1]=i;
            if(i%prime[j]==0)break;
        }
    }
}
void update(int x,int val)
{
    while(is[x])
    {
        num[fa[x][0]]+=val;
        x=fa[x][1];
    }
    num[x]+=val;
}
int _pow(int x,int y)
{
    int res=1;
    while(y)
    {
        if(y&1)res=(1LL*res*x)%mod;
        x=(1LL*x*x)%mod;
        y>>=1;
    }
    return res;
}
int cal()
{
    int res=1;
    for(int i=2;i<maxn;i++)
        if(num[i])res=(1LL*res*_pow(i,num[i]))%mod;
    return res;
}
int main()
{
    scanf("%d%d",&n,&mod);
    linear_shaker();
    for(int i=n+1;i<=2*n;i++)
        update(i,1);
    for(int i=2;i<=n;i++)
        update(i,-1);
    update(n+1,-1);
    printf("%d",cal());
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章