zoukankan      html  css  js  c++  java
  • P3200 [HNOI2009]有趣的数列

    题目:P3200 [HNOI2009]有趣的数列

    思路:

    打表可以发现是裸的Catalan数,简单证明一下:
    假设现在有两个vector s1、s2,s1依次存奇数位的数,s2存偶数位的数。
    例如:s1里存的是1,2,5;s2里存的是3,4,6;表示的就是数列1,3,2,4,5,6。
    根据题目要求,s1、s2都是递增的,并且最后s1、s2各存n个数。所以我们的操作就是把数字1~2n依次存入,每个数或存入s1尾部,或存入s2尾部。
    现在考虑相邻奇数位大于偶数位的限制:在我们依次存的过程中,如果哪一时刻,s1中的数多于s2中的数则无解(可手动模拟),所以对于合法情况,满足任意时刻s1的size都小于等于s2的size。向s1尾部加入数看做向上走,向s2尾部加入数看做向右走,转化为Catalan数的网格图模型。
    注意任意模数,可能没有逆元,所以可以分解质因数之后求解。


    Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e6+5;
    int n,mod,tot,mindiv[N],cnt[N],p[N];
    void Prime(){
    	for(int i=2;i<=2*n;++i){
    		if(!mindiv[i]) mindiv[i]=p[++tot]=i;
    		for(int j=1;j<=tot;++j){
    			if(i*p[j]>2*n||p[j]>mindiv[i]) break;
    			mindiv[i*p[j]]=p[j];
    		}
    	}
    }
    void add(int num){
    	while(num^1){
    		++cnt[mindiv[num]];
    		num/=mindiv[num];
    	}
    }
    void del(int num){
    	while(num^1){
    		--cnt[mindiv[num]];
    		num/=mindiv[num];
    	}
    }
    ll quickpow(ll a,ll b,ll p){
    	ll res=1;
    	while(b){
    		if(b&1) res=res*a%p;
    		a=a*a%p;
    		b>>=1;
    	}
    	return res%p;
    }
    ll Catalan(int n){
    	for(int i=n+2;i<=2*n;++i) add(i);
    	for(int i=1;i<=n;++i) del(i);
    	ll res=1;
    	for(int i=1;i<=tot;++i) res=res*quickpow(p[i],cnt[p[i]],mod)%mod;
    	return res;
    }
    int main(){
    	scanf("%d%d",&n,&mod);
    	Prime();
    	printf("%lld",Catalan(n));
    	return 0;
    }
    
  • 相关阅读:
    随笔35 内联函数
    随笔32 内部类,外部类,局部内部类
    随笔31 Spring的依赖注入的三种方式
    随笔30 抽象类与接口
    随笔29 Statement对象
    随笔28 Spring中的事务
    随笔27 面向对象的五大基本原则
    随笔26 java中的泛型
    html5学习笔记——HTML5 web存储
    html5学习笔记——HTML 5 视频
  • 原文地址:https://www.cnblogs.com/yu-xing/p/11221970.html
Copyright © 2011-2022 走看看