切割多边形

Description

在一个凸n边形中,通过不相交于n边形内部的对角线,把n边形拆分成若干三角形。现在的任务是从键盘输入凸多边形的边数n,求不同剖分的方案数Cn。

Analysis

困难的一题。

不谈1000的数据量加上大整数会不会TLE,先分析一下转移方程。

不妨以点为突破口。显而易见,每个点要么被连接,要么不被连接。

  • 当不被连接时,其相邻两点一定连接,则n边形转化为n-1边形。
  • 当被连接时,可以与n-3个点相连,那么相连之后分割出i边形和n-i+2边形。为了防止重复,即连接第i个点时要保证不连接i+1n-3,可以将n-i+2边形转化为n-i+1边形,即自动视为此点不与i+1n-3个点相连。

动规方程:

dp[i]=dp[i-1]+dp[3]*dp[i-2]+...+dp[i-1]*dp[2]

因为dp[2]=1,所以又可以写成

dp[i]=dp[2]*dp[i-1]+...+dp[i-1]*dp[2]

状态转移复杂度为O(n^2),再算上高精度处理O(1000),TLE。

那么,怎么通过O(n)乃至更小的复杂度转移状态呢。我不知道,所以看了hj解题报告,了解了Catlan Queue。

不进行证明。

Code

#include <bits/stdc++.h>

struct bigint{
	int len,num[5010];
	bigint operator = (int eq){
		len=0;
		memset(num,0,sizeof(num));
		while(eq){
			num[len++]=eq%10;
			eq/=10;
		}
		return *this;
	}
	bigint operator * (bigint mt){
		bigint ans;
		ans.len=len+mt.len-1;
		memset(ans.num,0,sizeof(ans.num));
		for(int i=0;i<len;i++)
			for(int j=0;j<mt.len;j++)
				ans.num[i+j]+=num[i]*mt.num[j];
		int add=0;
		for(int i=0;i<ans.len;i++){
			ans.num[i]+=add;
			add=ans.num[i]/10;
			ans.num[i]%=10;
		}
		while(add){
			ans.num[ans.len++]=add%10;
			add/=10;
		}
		return ans;
	}
	bigint operator * (int mt){
		bigint bigmt;
		bigmt=mt;
		return *this*bigmt;
	}
	bigint operator *= (int mt){
		return *this=*this*mt;
	}
	bigint operator / (int dv){
		bigint ans;
		ans.len=len;
		memset(ans.num,0,sizeof(ans.num));
		int bc=0;
		for(int i=len-1;i>=0;i--){
			bc=bc*10+num[i];
			if(bc>=dv)ans.num[i]=bc/dv,bc%=dv;
		}
		while(ans.len-1&&!ans.num[ans.len-1])ans.len--;
		return ans;
	}
	bigint operator /= (int dv){
		return *this=*this/dv;
	}
	friend std::ostream& operator << (std::ostream& out,bigint ans){
		for(int i=ans.len-1;i+1;i--)
			out<<ans.num[i];
		return out;
	}
};

int n;

bigint Catlan(int x){
	bigint ans;
	ans=x+2;
	for(int i=x+3;i<=x*2;i++)
		ans*=i;
	for(int i=2;i<=x;i++)
		ans/=i;
	return ans;
}

int main(){
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	std::cin>>n;
	if(n==1)std::cout<<0<<std::endl;
	else if(n<4)std::cout<<1<<std::endl;
	else std::cout<<Catlan(n-2)<<std::endl;
	return 0;
}
posted @ 2018-08-17 11:49  Srzer  阅读(286)  评论(0编辑  收藏  举报