BZOJ1485: [HNOI2009]有趣的数列
题解:考虑按顺序从小到大,加入数字,将加入奇数位置看作入栈,加入偶数位置看作出栈。为什么可以?考虑我们要保证相邻奇数小于偶数,所以必须先填上一个奇数的位置才能填偶数的位置,既时刻保证奇数>=偶数,最终奇数等于偶数。观察到这个性质,我们应该联想到卡特兰数了,套用公式求解。本题模数可能为合数,不一定存在逆元!!所以,要分解开计算,最后合并起来。顺便试了下常数优化。。。然而本人代码太丑,怕是救不回来了。
#include <bits/stdc++.h> typedef unsigned long long ull; using namespace std; int notp[2000007],num[2000007],nxt[2000007],n,P,p[2000007],tn; void init() { notp[1]=1;nxt[1]=1; tn = (n<<1); for(register int i=1;i<=tn;++i) { if(!notp[i])p[++p[0]]=i,nxt[i]=i; for(register int j=1;j<=p[0]&&p[j]*i<=tn;++j) { notp[i*p[j]]=1;nxt[i*p[j]]=p[j]; if(i%p[j]==0)break; } } } inline void add(ull a,ull v) { while(a != 1) { num[nxt[a]]+=v; a/=nxt[a]; } } inline ull q_pow(ull a,int b) { ull ans=1; while(b) { if(b&1)ans=(ans*a)%P; a=(a*a)%P; b>>=1; } return (int)ans; } inline ull merge() { ull ans = 1; register int i; for( i=1; i<=p[0]; i+=3) { ans = (ans%P*q_pow(p[i],num[p[i]])%P)%P; ans = (ans%P*q_pow(p[i+1],num[p[i+1]])%P)%P; ans = (ans%P*q_pow(p[i+2],num[p[i+2]])%P)%P; } for(;i<=p[0];++i) ans = (ans%P*q_pow(p[i],num[p[i]])%P)%P; return ans%P; } inline void write(ull x) { if(x>=10)write(x/10); putchar(x%10+'0'); } // (while) better than (for) // (!=) better than (>) // (int) better than (ull) better than (ll) int main() { scanf("%d%d",&n,&P); init(); for(ull i=1;i<=tn;++i) add(i,1); for(ull i=1;i<=n;++i) add(i,-2); add(n+1,-1); write(merge()); }