[POI2007]对称轴

[POI2007]对称轴

题意:

按照图的顺序,给定n个点的多边形,求对称轴数,x,y是整点在1e8范围内,n 在 100000 范围内

solution:

这个一看就有种图形一半一半匹配的感觉,想想快速求两块相等并且保证这题复杂度正确
一开始考虑的分治,或者是有某种数学结论。
后来想着可能可以用manacher这种字符串配对算法配对,越想越可以,但是考试写的代码太麻烦了,后面重写了遍。
考虑现在在一个点,那么这个图形对称的条件就是左右两边的边和角度都要分别相等
在一个边也是同样的,那么这题就直接生成一个点边点边的数列跑manacher就行
有一个问题是不管是cos还是叉乘判断角度,都会有个问题,就是图形内的两个相加等于360度的角求出来值相等,这样没法判断,但是yy一下x,y是整点,可以发现不会有这种情况。就可以放心写了,有点细节注意一下就好了
另外我直接用int,因为是匹配,所以int会自动帮我们哈希,就不用管了
代码:

#include<algorithm>
#include<iostream>
#include<cstdio>
#define ll long long
#define R register
using namespace std;
const int N = 100005;
template<class T>
void rea(T &x)
{
	char ch=getchar();int f(0);x = 0;
	while(!isdigit(ch)) {f|=ch=='-';ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	x = f?-x:x;
}
int T, n, s[N*5], f[N*5];
struct node { int x, y; } d[N];
int dis(node a, node b) {return (b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y);}
int cro(node a, node b, node c) {return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);}
int main()
{
	rea(T);
	while(T --> 0)
	{
		rea(n);
		for(R int i = 1; i <= n; ++i) rea(d[i].x), rea(d[i].y);
		for(R int i = 1; i <= n; ++i) 
			s[i*2-1] = cro(d[i], (i==1?d[n]:d[i-1]), (i==n?d[1]:d[i+1]));
		for(R int i = 1; i <= n; ++i)
			s[i*2] = dis(d[i], (i==n?d[1]:d[i+1]));
		for(R int i = 1; i <= n; ++i) 
			s[i+n*2] = s[i];
		int mid = 0, mx = 0, ans = 0;
		for(R int i = 0; i <= 2*n; ++i) f[i] = 0;
		for(R int i = 1; i <= 2*n; ++i)
		{
			if(i <= mx) f[i] = min(f[2*mid-i], mx-i+1); else f[i] = 1;
			while(s[i+f[i]] == s[i-f[i]] && i+f[i] <= 3*n && i-f[i] >= 1) ++f[i];
			if(i+f[i]-1 > mx) mx = i+f[i]-1, mid = i;
			if(f[i] >= n+1) ans++;
		}
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2020-02-29 23:01  Chopsticks  阅读(103)  评论(0编辑  收藏  举报