Problem K. Kingdom Division 2

Problem K. Kingdom Division 2
Input le: kingdom.in
Output le: kingdom.out
Time limit: 2 seconds
Memory limit: 256 megabytes
Once upon a time there was a kingdom ruled by a wise king. After forty years of his reign, by means of
successful military actions and skillful diplomacy, the kingdom became a convex polygon with n vertices.
This form of the kingdom greatly simplied tax collection and land division between the inhabitants, so
everybody was happy.
But nothing lasts forever, and one autumn evening the king suddenly died. Due to the laws of the kingdom,
the oldest son of the king should have taken the kingdom, but the problem was that he had two twin
sons. It was widely known that the king loved his sons equally, so it was not even pronounced to choose
only one son to rule.
After ten days of serious thoughts it was nally decided to split the kingdom into two parts one per
each son. Remembering the sad story of another kingdom that tried to divide the kingdom into two parts
of equal area, wise men of the kingdom in this problem decided to use another way of kingdom division.
There are two cities in the kingdom, Andrewville and Bettyburg. It was decided to divide the kingdom
by a straight line in such way that:
• The line connects two vertices of the polygon.
• Andrewville and Bettyburg are strictly inside of the parts that the polygon is divided to, and belong
to dierent parts.
However it turned out that there are several ways to do the division. People of the kingdom don't know
how to choose the optimal way to do it, so they rst decided to count the number of ways. Help them to
do it.
Input
The input le contains several test cases. Each test case starts with n the number of vertices of the
polygon (4 ≤ n ≤ 100 000). The following n lines contain vertices of the polygon in counterclockwise
order. No three vertices are on the same line.
Two lines follow, containing coordinates of Andrewville and Bettyburg, respectively. The cities are at
dierent points strictly inside the given polygon.
Coordinates of all points do not exceed 109 by their absolute values.
The last test case is followed by n = 0, it must not be processed.
The sum of n for all test cases in the input le is at most 100 000.
Output

For each test case output one integer the number of ways to divide the kingdom.

Example: 

Input:5
0 0
6 0
6 4
3 6
0 4
4 1
1 4
4
0 0
4 0
4 4
0 4
1 1
3 1
0

Output:

3

0

:

题目大概意思是有一个n点的凸包,内部有两个点a、b,要求连接任意两个顶点,使得:1.凸包被分成两部分;2.两个点a、b在不同的子块里

划一下图大概就能看出来,对于某一个顶点x来说,能和它完成匹配的点在射线xa和xb的夹缝中间,所以这是一个查找问题,通过比较斜率,

然后找出来夹缝中距离x点l1和l2长度的两个最接近射线边界的点,则其中符合条件的点的个数是l1和l2的差,最后所有的和相加除以2就可以了,

因为n的基数比较大,所以用二分查找

/*PROBLEM K : "SOLVED" */
/*TIME : ______________*/
#include "cstdio"
#include "cstring"
#include "cctype"
#include "algorithm"
#include "cmath"
#include "vector"
using namespace std;

#define Inc(i, a, b) for(int i = a; i < b; i++)
#define Dec(i, a, b) for(int i = a; i > b; i--)
#define Mem(a, x) memset(a, x, sizeof(a))
#define Pii pair<int, int> 
#define Pdd pair<double, double>
#define Cin scanf
#define Put printf
#define CIN(a) scanf("%d", &a)
#define CII(a, b) scanf("%d%d", &a, &b)
#define CIS(a) scanf("%s", a)
#define PUT(a) printf("%d\n", a) 
#define PII(a, b) printf("%d %d\n", a, b)
#define PUS(a) printf("%s\n", a)
#define Pub push_back
#define Mpi make_pair
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
#define ll long long
#define maxn 100005
#define pi acos(-1)
#define eps 1e-10
struct Point {
	int x, y;
	Point() {}
	Point(int x, int y) : x(x), y(y) {}
} ;
Point point[maxn];
Point a, b;
int n;
//void solve
ll xmul(Point p0, Point p1, Point p2) {
	return (ll)(p1.x - p0.x) * (p2.y - p0.y) - (ll)(p2.x - p0.x) * (p1.y - p0.y);
}
ll cala(int t) {
	int l = 1, r = n - 1;
	while(l < r) {
		int mid = (l + r) >> 1;
		if(xmul(point[t], point[(t + mid) % n], a) < 0 || xmul(point[t], point[(t + mid) % n], b) < 0)
			r = mid;
		else l = mid + 1;
	}
	ll l1 = xmul(point[t], point[(t + l) % n], a);
	ll l2 = xmul(point[t], point[(t + l) % n], b);
	if((l1 < 0 && l2 < 0) || (l1 >= 0 && l2 >= 0)) return -1;
	return l;
}
ll calb(int t) {
	int l = 1, r = n - 1;
	while(l < r) {
		int mid = (l + r) >> 1;
		if(xmul(point[t], point[(t + mid) % n], a) > 0 || xmul(point[t], point[(t + mid) % n], b) > 0)
			l = mid + 1;
		else r = mid;
	}
	return l;
}
void Solve() {
	ll ans = 0;
	Inc(i, 0, n) {
		ll t1 = cala(i);
		if(t1 < 0) continue;
		ll t2 = calb(i);
		ans += t2 - t1;
	}
	Put("%lld\n", ans / 2);
}
int main() {
	freopen("kingdom.in", "r", stdin);
	freopen("kingdom.out", "w", stdout);
	while(CIN(n), n) {
		Inc(i, 0, n) CII(point[i].x, point[i].y);
		CII(a.x, a.y); CII(b.x, b.y);
		Solve();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值