【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);
}

 

posted @ 2017-08-08 07:39  TS_Hugh  阅读(279)  评论(0编辑  收藏  举报