[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; }