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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章