hdoj 4828 卡特兰数取模

Grids

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 93    Accepted Submission(s): 25


Problem Description
  度度熊近期非常喜欢玩游戏。这一天他在纸上画了一个2行N列的长方形格子。

他想把1到2N这些数依次放进去。可是为了使格子看起来优美,他想找到使每行每列都递增的方案。只是画了非常久,他发现方案数实在是太多了。度度熊想知道,有多少种放数字的方法能满足上面的条件?

 

Input
  第一行为数据组数T(1<=T<=100000)。
  然后T行,每行为一个数N(1<=N<=1000000)表示长方形的大小。
 

Output
  对于每组数据,输出符合题意的方案数。

因为数字可能很大,你仅仅须要把最后的结果对1000000007取模就可以。

 

Sample Input
2 1 3
 

Sample Output
Case #1: 1 Case #2: 5
Hint
对于第二组例子。共5种方案,详细方案为:
 

Source

通过打表得出前7项分别为1,2,5,14,42,132,429。可知答案为卡特兰数h(n)=C(2n,n)/(n+1)=h(n-1)*(4*n-2)/(n+1)。

一開始採用组合数分解素因子+二分求幂求组合数取模,但是会TLE。组合数求模相关知识http://hi.baidu.com/aekdycoin/item/e051d6616ce60294c5d249d7。渣代码例如以下:

#include <stdio.h>
#include <string>
#include <iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 2000005;
const int n=148955;
bool a[N];//a[]的长度比pr[]的长度长得多
int pr[n];
#define MOD 1000000007
int num;
void Prime2()
{
    memset(a, 0, N*sizeof(a[0]));
    int i, j;
	num = 0;
    a[0]=a[1]=1;
    for(i = 2; i < N; ++i)
	{
        if(!(a[i])) pr[num++] = i;
        for(j = 0; (j<num && i*pr[j]<N); ++j)
		{
            a[i*pr[j]] = 1;
            if(!(i%pr[j])) break;
        }
    }
}
int val[n],len;
void calcJC(int n,int id,int flag){
	int ans=0,y,p=pr[id];
	while(n){
		y=n/p;
		ans+=y;
		n=y;
	}
	val[id]=val[id]+ans*flag;
}
__int64 extgcd(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    __int64 r=extgcd(b,a%b,x,y);
    __int64 t=x;x=y;y=t-a/b*y;
    return r;
}
int MPow(int p,int e){
	if(e==0)return 1;
	else if(e==1)return p;
	int t=p,ans=1;
	while(e){
		if(e&1)ans=(ans*t)%MOD;
		t=(t*t)%MOD;
		e>>=1;
	}
	return ans;
}
int main()
{
	Prime2();
	int txt,l=1,k,i;
	__int64 ans,x,y;
	scanf("%d",&txt);
	while(txt--){
		scanf("%d",&k);
		memset(val,0,sizeof(val));
	 	for(i=0;pr[i]<=2*k;++i)
			calcJC(2*k,i,1);
		for(i=0;pr[i]<=k;++i)
			calcJC(k,i,-2);
		ans=1;
		for(i=0;pr[i]<=2*k;++i){
		//	if(val[i]>0)printf("%d^%d ",pr[i],val[i]);
			ans=(ans*MPow(pr[i],val[i]))%MOD;
		}
		extgcd(k+1,MOD,x,y);
		x=(x+MOD)%MOD;
		ans=(ans*x)%MOD;
		printf("%I64d
",ans);
	}
	return 0;
}

无奈,看到n范围不是非常大,直接打表吧、、、

#include <stdio.h>
#include <string>
#include <iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
#define MOD 1000000007
const int N = 1000001;
int a[N];
__int64 extgcd(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    __int64 r=extgcd(b,a%b,x,y);
    __int64 t=x;x=y;y=t-a/b*y;
    return r;
}
void calcCATALAN(int n){
	__int64 x,y;
	a[1]=1;
	int i;
	for(i=2;i<n;++i){
		x=a[i-1];
		a[i]=(x*(4*i-2))%MOD;
		extgcd(i+1,MOD,x,y);
		x=(x+MOD)%MOD;
		a[i]=(a[i]*x)%MOD;
	}
}
int main()
{
	calcCATALAN(N);
	int txt,l=1,k;
	scanf("%d",&txt);
	while(txt--){
		scanf("%d",&k);
		printf("Case #%d:
",l++);
		printf("%d
",a[k]);
	}
	return 0;
}


原文地址:https://www.cnblogs.com/gccbuaa/p/7222500.html