CF437E The Child and Polygon

Posted jeefy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF437E The Child and Polygon相关的知识,希望对你有一定的参考价值。

The Child and Polygon 题解

这世界这么大,遇到了这个奇奇怪怪的题。

这道题其实可以很自然的联想到卡特兰数。

在卡特兰数的计数中,有这么一个意义:\\(C_n\\) 表示把有 \\(n+2\\) 条边的凸多边形分成 \\(n\\) 个三角形的方案数。

利用这个意义可以得到 \\(C_n\\) 的另一个递推关系:

\\[C_n = \\sum_k = 0^n - 1 C_k C_n-1-k \\]

而这一道题,正可以类比这个递推关系进行求解。

思路

在卡特兰数递推中,\\(k\\) 实际上枚举的是最后一次的分界点。也就是把整个多边形分成两部分,分别划分,再求最终方案数。

首先我们将已知的 \\(n\\) 个点按照顺时针方向排好序。

类比下来,我们可以設 \\(f_i, j\\) 表示由 \\(i \\sim j\\)\\(j - i + 1\\) 个点形成的多边形的划分数。

于是

\\[f_i, j = \\sum_k = i^j f_i, k f_k, j [i 可以连向 k] \\]

这里 \\(i\\) 可以连向 \\(k\\) 当且仅当线段 \\(\\vecij\\) 在线段 \\(\\vecik\\) 的顺时针方向。

于是本题的核心思路就已经出来了。接下来考虑实现问题。

实现

逆时针,顺时针?

我们可以通过向量叉乘的方法来判断所给的点是顺时针还是逆时针。

考虑按照所给的点的顺序计算这个多边形的面积。

枚举 \\(i\\) 利用 \\(\\vec1i\\)\\(\\vec1(i+1)\\) 的叉乘,可以算出整个多边形的面积(的两倍)。

但是考虑到叉乘的正负性,如果结果为正,则所给的顺序为逆时针(因为 \\(\\vec1i\\)\\(\\vec1(i+1)\\) 的顺时针方向)。

此时就可以搞定逆时针,顺时针的问题了。

可连?不可连?

在前面已经提到,\\(i\\) 可以连向 \\(k\\) 的条件,如何判断?

还是利用 \\(\\vecij \\times \\vecik\\),如果结果为正,则 \\(\\vecij\\)\\(\\vecik\\) 的顺时针方向,可以连。


于是你成功的可以 \\(\\texttt\\colorbox#52C41A\\textcolorwhiteAC\\) 本题了。

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int N = 203, mod = 1e9 + 7;
typedef long long lint;
struct Point 
	int x, y;
	Point() 
	Point(int x, int y) : x(x), y(y) 
	inline lint operator * (const Point &p) 
		return (1ll * x * p.y - 1ll * y * p.x);
	

	inline Point operator - (const Point &p) 
		return Point(x - p.x, y - p.y);
	
 p[N];

lint dp[N][N];

int main() 
	cin.tie(0)->sync_with_stdio(false);

	int n; cin >> n;
	for (int x, y, i = 1; i <= n; ++i) 
		cin >> x >> y;
		p[i] = Point(x, y);
	

	lint clockwiser = 0;
	for (int i = 2; i < n; ++i) 
		clockwiser += (p[i] - p[1]) * (p[i + 1] - p[1]);
	

	if (clockwiser > 0) // if is positive, the it is counterclockwise
		reverse(p + 1, p + 1 + n);

	for (int i = 1; i < n; ++i)
		dp[i][i + 1] = 1;

	for (int len = 2; len < n; ++len) 
		for (int l = 1, r = len + 1; r <= n; ++l, ++r) 
			for (int k = l; k <= r; ++k) 
				if ((p[r] - p[l]) * (p[k] - p[l]) > 0)
					dp[l][r] = (dp[l][r] + 1ll * dp[l][k] * dp[k][r] % mod) % mod;
			
		
	

	cout << dp[1][n] << \'\\n\';


A. The Child and Homework

 

http://codeforces.com/contest/437/problem/A

 

 1 import java.util.ArrayList;
 2 import java.util.Scanner;
 3 
 4 public class Main 
 5 
 6     public static void main(String[] args) 
 7         Scanner in = new Scanner(System.in);
 8         while (in.hasNext())
 9             int[]len=new int[4];
10             int[]min=new int[4];
11             int[]max=new int[4];
12             for (int i = 0; i < 4; i++) 
13                 String s=in.nextLine();
14                 while (s.length()==0)s=in.nextLine();
15                 len[i]=s.length()-2;
16             
17             for (int i = 0; i < 4; i++) 
18                 for (int j = 0; j < 4; j++) 
19                     if (j==i)continue;
20                     if (len[j]>=len[i]*2)min[i]++;
21                     if (len[j]*2<=len[i])max[i]++;
22                 
23             
24             ArrayList<Integer>al=new ArrayList<>();
25             for (int i = 0; i < 4; i++) if (min[i]==3||max[i]==3)al.add(i);
26             if (al.size()!=1) System.out.println("C");
27             else System.out.println((char)(al.get(0)+‘A‘));
28         
29     
30 

 

以上是关于CF437E The Child and Polygon的主要内容,如果未能解决你的问题,请参考以下文章