zoukankan      html  css  js  c++  java
  • BZOJ 1485: [HNOI2009]有趣的数列(卡特兰数)

    传送门

    解题思路

      因为总共是一个排列,那么确定了奇数项是哪些,偶数项就确定了。怎么判断奇数项是否合法呢,其实由于第三个限制,可以把这个数列看成一个括号序列,奇数项为((),偶数项为()),那么合法方案数自然是卡特兰数了。。模数不是质数,而且(n^2)会超时,就只能用(ans=frac{dbinom{2n}{n}}{n+1})这个式子了,化简一下就是(ans=dfrac{prodlimits_{i=n+2}^{2n}i}{prodlimits_{i=1}^ni}),然后筛一下质数,把这个式子拆成若干个素数次幂乘积形式,然后快速幂就能做了。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    const int MAXN = 2000005;
    typedef long long LL;
    
    int n,MOD,cnt[MAXN],tot,prime[MAXN];
    int vis[MAXN],ans=1;
    
    inline int fast_pow(int x,int y){
    	int ret=1;
    	for(;y;y>>=1){
    		if(y&1) ret=(LL)ret*x%MOD;
    		x=(LL)x*x%MOD;	
    	}
    	return ret;
    }
    
    int main(){
    	scanf("%d%d",&n,&MOD);vis[1]=1;
    	for(int i=2;i<=2*n;i++){
    		if(!vis[i]) vis[i]=i,prime[++tot]=i;
    		for(int j=1;j<=tot && (LL)i*prime[j]<=2*n;j++){
    			vis[i*prime[j]]=prime[j];
    			if(!(i%prime[j])) break;
    		}
    	}
    	for(int i=2;i<=n;i++) cnt[i]=-1;
    	for(int i=n+2;i<=n*2;i++) cnt[i]=1;
    	for(int i=n*2;i>1;i--) {
    		if(vis[i]==i) ans=((LL)ans*fast_pow(i,cnt[i])%MOD);
    		else cnt[vis[i]]+=cnt[i],cnt[i/vis[i]]+=cnt[i];	
    	}
    	printf("%d
    ",ans);
    	return 0;	
    }
    
  • 相关阅读:
    [CF786B] Legacy
    [CF833B] The Bakery
    [JSOI2008] 最小生成树计数
    [SDOI2010] 外星千足虫
    [POJ1830] 开关问题
    [Luogu1365] WJMZBMR打osu! / Easy
    [Noip2016] 换教室
    [NOI2002] 荒岛野人
    [计蒜之道复赛 2018] 贝壳找房计数比赛
    [SDOI2014] 旅行
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10067304.html
Copyright © 2011-2022 走看看