【BZOJ 1485】[HNOI2009]有趣的数列 卡特兰数
这个题我是冲着卡特兰数来的所以就没有想到什么dp,当然也没有想到用卡特兰数的原因...........
你只要求出前几项就会发现是个卡特兰数,为什么呢:我们选择地时候要选择奇数位和偶数位,相邻(一对里面)奇数位小于偶数位而且他们内部分别递增,那么就是在一个1~2*n的数列上选取一些书作为左括号,一些数作为右括号,左括号为奇数位右括号为偶数位,且是合法的匹配因为都是n个,所以我们就是在进行n对括号匹配。
这道题的分解质因数就用组合数求就好了。就是先筛质数并记录一个数的最小质因子,然后跳着筛,并记录质数个数,最后在对质数进行快速幂(不快速幂也行而且或许更优),效率是O(n*不可忽略的某常数)..
#include <cstdio> #include <cstring> using namespace std; typedef int LL; const LL N=2000010; LL prime[N],size[N],p,n,len,num[N]; bool isnot[N]; void Pre(){ for(LL i=2;i<=(n<<1);i++){ if(!isnot[i])prime[++len]=i,num[i]=len; for(LL j=1;prime[j]*i<=(n<<1);j++){ isnot[prime[j]*i]=1,num[prime[j]*i]=j; if(i%prime[j]==0)break; } } } void get(LL x,LL s){ while(x!=1){ size[num[x]]+=s; x/=prime[num[x]]; } } inline void Pow(long long &ans,LL x,LL y){ while(y){ if(y&1)ans=ans*x%p; y>>=1,x=x*x%p; } } int main(){ scanf("%d%d",&n,&p);Pre(); for(LL i=n+2;i<=(n<<1);i++)get(i,1); for(LL i=2;i<=n;i++)get(i,-1); register long long ans=1; for(LL i=1;i<=len;i++) if(size[i]) Pow(ans,prime[i],size[i]); printf("%lld",ans); }
苟利国家生死以, 岂因祸福避趋之。