[AHOI2012]树屋阶梯

做题时间:2022.7.5

\(【题目描述】\)

给定一个高为 \(N(1\leq N\leq 500)\) 的阶梯型(如图是高度为4的阶梯型)

将其划分为 \(N\) 个矩形(划分线必须与网格线重合),问方案数。

\(【输入格式】\)

一个整数 \(N\)

\(【输出格式】\)

一个整数表示方案数

\(【考点】\)

卡特兰数列,高精度

\(【做法】\)

枚举前3项可以发现是\(1,2,5\) ,很有可能是卡特兰数列。原题是几何类问题,可以考虑类比凸 \(n+2\) 边形问题(catalan的经典问题)。

由于右上角有 \(N\) 个拐角,题目又要求划分为 \(N\) 个矩形,因此每一个矩形覆盖住一个拐角,也就是说没有矩形放在阶梯型中间而不与拐角接触。

考虑左下角的一格,设覆盖住这一格的矩形大小为 \(a\times b\) ,这个大阶梯型就被分成了左上角一个高为 \(N-a\) 的阶梯型,中间一个 \(a\times b\) 的矩形,右下角一个高为 \(N-b\) 的阶梯型,很想凸 \(n+2\) 边形问题,递归求解即可。

注意要写压位高精

\(【代码】\)

#include<cstdio>
#include<iomanip>
#include<cstring>

using namespace std;
typedef long long ll;
const int N=1e3+50,BIT=1000000000;
inline int Max(int a,int b){return a>b?a:b;} 
struct BigNum{
	ll num[N];
	int len;
	BigNum(){
		memset(num,0,sizeof(num));
		len=0;
	}
	BigNum operator +(const BigNum b){
		BigNum c;
		c.len=Max(len,b.len);
		for(int i=1;i<=c.len;i++){
			c.num[i]+=num[i]+b.num[i];
			if(c.num[i]>=BIT) c.num[i]-=BIT,c.num[i+1]++; 
		}
		if(c.num[c.len+1]) c.len++;
		return c;
	}
	BigNum operator *(const BigNum b){
		BigNum c;
		c.len=len+b.len;
		ll x=0;
		for(int i=1;i<=len;i++){
			for(int j=1;j<=b.len;j++){
				c.num[i+j-1]+=num[i]*b.num[j]+x;
				x=c.num[i+j-1]/BIT,c.num[i+j-1]%=BIT;
			}
			if(x) c.num[b.len+i]=x;
			x=0;
		}
		while(!c.num[c.len]&&c.len>1) c.len--;
		return c;
	}
}H[N];
int n;
void Print(BigNum ans)
{
	for(int i=ans.len;i>=1;i--){//压位高精输出
		if(i==ans.len) printf("%lld",ans.num[i]);
		else printf("%09lld",ans.num[i]);
	}
	printf("\n");
}
int main()
{
	scanf("%d",&n);
	H[0].len=1,H[0].num[1]=1;
	H[1].len=1,H[1].num[1]=1;
	for(int i=2;i<=n;i++){//卡特兰数递推公式
		for(int j=0;j<=i-1;j++) H[i]=H[i]+(H[j]*H[i-j-1]);
	}
	Print(H[n]);
	return 0;
}
posted @ 2022-07-06 09:33  lxzy  阅读(57)  评论(0)    收藏  举报