• 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;	
    }
    
  • 相关阅读:
    单元测试之mock使用
    Linux命令 diff 命令(比较文件的差异)
    @ComponentScan自动扫描组件介绍
    AES 加解密 & RSA加解密
    vxetable结合ElementUI单元格样式
    uniapp打开新的网页页签
    input等通过样式禁用
    elementui 时间选择限制当天之前的时间不可选择
    符号位扩展
    函数指针数组的运用
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10067304.html
Copyright © 2020-2023  润新知