[BZOJ1485] 有趣的数列 (卡特兰数)

首先要明确这是卡特兰数,证明如下:

我们可以把奇数项和偶数项看成2个数列,然后从1到2*n扫一边可以往2个数列里塞,但必须满足奇数项的个数时刻大于等于偶数项个数(小的话就不能让奇数项小于偶数项了),于是便巧妙地出栈顺序问题吗即卡特兰数。


 

看到p不一定是素数,便想到了exlucas,打完交上去TLE80,这时才看见数据范围是:

n<=1e6,p<=1e9!f**k!

这么大的模数exface啊?(exskyh)

在无奈之中颓了Deepinc的题解发现质因数分解可以线筛+递归处理,学到了学到了。。。


 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<vector>
#define int long long 
using namespace std;
const int N=2e6+10;
int ans=1,cnt,n,p,a[N],prime[N],mark[N],f[N];
void init(int x,int y)
{
        if(x==1) return;
        a[f[x]]+=y;
        init(x/f[x],y);
}
int poww(int x,int y,int z)
{
        int sum=1;
        while(y)
        {
                if(y&1) sum=(sum*x)%z;
                y>>=1;
                x=(x*x)%z;
        }
        return sum;
}
main()
{
        //freopen("1.in","r",stdin);
        scanf("%lld%lld",&n,&p);
        for(int i=2;i<=n*2;i++)
        {
                if(!mark[i])
                {
                        prime[++cnt]=i;
                        f[i]=i;
                }
                for(int j=1;j<=cnt;j++)
                {
                        if(i*prime[j]>n*2) break;
                        f[i*prime[j]]=prime[j];
                        mark[i*prime[j]]=1;
                        if(i%prime[j]==0) break;
                }
        }
        for(int i=n+2;i<=n*2;i++) init(i,1);
        for(int i=2;i<=n;i++) init(i,-1);
        for(int i=2;i<=n*2;i++) ans=ans*poww(i,a[i],p)%p;
        printf("%lld",ans);
        return 0;
}

 

posted @ 2019-07-21 17:22  ATHOSD  阅读(161)  评论(0编辑  收藏  举报