蛋糕(卡特兰数)

题目描述


输入格式

一行两个整数 n 和 P, 意义如题面所示。

输出格式

一行一个整数, 表示有多少种切法。

输入样例

【样例一输入】
6 1000000007

输出样例

【样例一输出】
14

题解:

       我们用f[i-2]来表示将凸i边形划分的方案数,那么我们设一个凸n边形的顶点顺时针顺序依次为p1,p2……pn,显然p1和pn相邻。现在我们选点pk,(k不为1和n),那么p1,pn,pk会把图形分成两部分+p1pnpk这个三角形,特殊的,当k=n-1或k=2时,我们把它看成分成了一个n-1边形和一个0边形。又因为0边形无法划分,我们暂定f[0]=1(表示0边形的划分数)。且由常识可知f[1]=1。

       现在我们就可以得出递推式:f[i-2]=f[0]*f[i-3]+f[1]*f[i-4]+……+f[i-3]*f[0];由此可观察出这就是我们所熟悉的卡特兰数,求n边形的划分方案,就是求卡特兰数的第n-2项。

       在这里先介绍一下卡特兰数的数学递推式:

       h(n)=C(2n,n)/(n+1)    h(n)=h(n-1)*(4*n-2)/(n+1);   h(n)=c(2n,n)-c(2n,n-1)

       接下来就好简单啦,不就求第n-2项吗?

       等等,真的简单吗?对于本题,n<=10,000,000,而且mod的p还不是质数!!!

       假如我们质因数分解,用最小表示法处理f[n-2],时间复杂度高达O(nlogn),所以我们必须找更优的方法。

       我们的最终目的是用最小表示法表示f[n-2],那么我们只需知道每个质数出现的个数就ok了。比如质数2,1-n中出现2的有n/2次,出现2^2的有n/4次,……,所以质数2出现的次数为

n/2+n/4+……+n/2^m,所以贴代码(这个需要自己理解一下):

#include<algorithm>
#include<fstream>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

int n,p,tot,pri[10000010],vis[20000020];
long long mi[10000010];
long long ans;

void Make_pri()
{
    for (int i=2; i<=2*n; i++)
    {
        if (vis[i]==0) {tot++; pri[tot] = i;}
        for (int j=1; j<=tot; j++)
        {
            long long x = (long long)pri[j]*(long long)i;
            if (x>2*n) break;  
            vis[x] = 1;
            if (i%pri[j]==0) break;
        }
    }
}

void Add(int len,int cur)
{
    for (int i=1; i<=tot; i++)
    {
        long long k = pri[i];
        while (k<=len)
        {
            mi[i]+=(long long)cur*(long long)(len/k);
            k = k*pri[i];
        }
    }
}

void Fast_mi()
{
    for (int i=1; i<=tot; i++)
    {
        long long a = pri[i],b = mi[i];
        while (b>0)
        {
            if (b%2==1) ans = ((long long)ans*(long long)a)%p;
            b = b/2;  a = ((long long)a*(long long)a)%p;
        }
    }
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    scanf("%d%d",&n,&p);
    Make_pri();  
    n = n-2;
    Add(2*n,1);  
    Add(n,-1);  Add(n+1,-1);  ans = 1;
    Fast_mi();
    printf("%I64d\n",ans);
    return 0;
}

 

posted @ 2017-09-25 16:22  最终惊吓者——Janous  阅读(268)  评论(0编辑  收藏  举报