【题解】P3454 [POI2007]OSI-Axes of Symmetry (几何+马拉车/manacher)

[POI2007]OSI-Axes of Symmetry

题目传送门 [POI2007]OSI-Axes of Symmetry

题面翻译

题目描述

Johnny 是一位非常年轻的数学家,但他此刻正在为他妹妹的数学作业烦恼。

这个周末,他的妹妹需要完成一项作业,计算各种几何图形的对称轴数量。因为 Johnny 这个周末想要去海边旅行,所以他希望他的妹妹能尽快完成这项作业。

于是他找到了擅长编程的你,你一定能帮助他完成这项任务的!

输入格式

输入包含多组数据。

第一行包含一个整数 \(t\),代表数据的组数。

对于每组数据,第一行一个整数 \(n\),代表多边形的顶点数。

接下来 \(n\) 行,每行两个整数 \(x_i,y_i\),代表每个顶点的坐标。

输入中的第 \(i\) 个顶点会与第 \(i+1\) 个顶点连一条边。特别地,输入中的第 \(n\) 个顶点会与第一个顶点连一条边。

输入给出的多边形不保证是凸多边形,但是保证任意两条边只会在端点处相交,且任意两条相邻的边不共线。

输出格式

对于每组数据,输出一行一个整数,即多边形对称轴的数量。

数据范围

\(1 \leq t \leq 10\)\(3 \leq n \leq 10^5\)\(-10^8 \leq x_i,y_i \leq 10^8\)

题目描述

Little Johnny - a well-respected young mathematician - has a younger sister, Justina. Johnny likes hissister very much and he gladly helps her with her homework, but, like most scientific minds, he does mindsolving the same problems again. Unfortunately, Justina is a very diligent pupil, and so she asks Johnny toreview her assignments many times, for sake of certainty. One sunny Friday, just before the famous LongMay Weekend1 the math teacher gave many exercises consisting in finding the axes of symmetry of variousgeometric figures. Justina is most likely to spend considerable amount of time solving these tasks. LittleJohnny had arranged himself a trip to the seaside long time before, nevertheless he feels obliged to help hislittle sister. Soon, he has found a solution - it would be best to write a programme that wouldease checking Justina's solutions. Since Johnny is a mathematician, not a computer scientist, and you are hisbest friend, it falls to you to write it.

Task

Write a programme that:

  • reads the descriptions of the polygons from the standard input,

  • determines the number of axes of symmetry for each one of them,

  • writes the result to the standard output.

给定一个多边形,求对称轴数量。

输入格式

In the first line of the input there is one integer \(t\) (\(1 \le t \le 10\)) - it is the number of polygons, for which the number of axes of symmetry is to be determined. Next, \(t\) descriptions of the polygons follow. The first line of each description contains one integer \(n\) (\(3 \le n \le 100\ 000\)) denoting the number of vertices of the polygon. In each of the following \(n\) lines there are two integers \(x\) and \(y\) (\(-100\ 000\ 000 \le x, y \le 100\ 000\ 000\)) representing the coordinates of subsequent vertices of the polygon. The polygons need not be convex, but they have no self-intersections - any two sides have at most one common point - their common endpoint, if they actually share it. Furthermore, no pair of consecutive sides is parallel.

输出格式

Your programme should output exactly \(t\) lines, with the \(k\)'th line containing a sole integer \(n_k\) - the number of axes of symmetry of the \(k\)'th polygon.

样例 #1

样例输入 #1

2
12
1 -1
2 -1
2 1
1 1
1 2
-1 2
-1 1
-2 1
-2 -1
-1 -1
-1 -2
1 -2
6
-1 1
-2 0
-1 -1
1 -1
2 0
1 1

样例输出 #1

4
2

思路

blabla...

代码实现

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6;
#define int long long
int n,ans,x[N*2],y[N*2],p[N*2],lx,ly;

inline int dis(int a,int b)//算两点距离平方
{
	return (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]);
}

inline bool check(int l,int i,int r)
{
	if(dis(l,i)!=dis(i,r)) return false;
	int ax=(x[l]+x[r])/2-x[i],
	    ay=(y[l]+y[r])/2-y[i];
	if(ax*ly!=ay*lx) return false;
	lx=ax,ly=ay;
	return true;
}

void manacher()
{
	int mid=0,mr=0;
	for(int i=1;i<=4*n;i++)
	{
		if(i<mr) p[i]=min(p[mid*2-i],mr-i);
		else p[i]=0;
		lx=ly=0;
		while(check(i-p[i]-1,i,i+p[i]+1)) ++p[i];
		if(i+p[i]>mr)
		{
			mr=i+p[i];
			mid=i;
		}
		ans+=(p[i]>=n);
	}
}

signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
	
		cin>>n;
		for(int i=1;i<=2*n;i+=2)
		{
			int a,b;
			cin>>a>>b;
			x[i]=a*4,y[i]=b*4;//为了防止接下来的计算出现取整为零的情况,可以用这个取代double
		}
		
		for(int i=2*n+1;i<=4*n;i+=2)//复制一遍
		{
			x[i]=x[i-2*n];
			y[i]=y[i-2*n];
		}
		
		x[4*n+1]=x[1],y[4*n+1]=y[1];
		
		for(int i=2;i<=4*n;i+=2)//计算边的中点坐标,对称轴可能在边上
		{
			x[i]=(x[i-1]+x[i+1])/2;
			y[i]=(y[i-1]+y[i+1])/2;
		}
		x[0]=520,y[0]=520,x[4*n+1]=521,y[4*n+1]=521;//边界,其实根本到不了边界 不设也行
		ans=0;
		manacher();
		
		cout<<ans/2<<endl;;
	}
	
	
	
	
	return 0;
}

posted @ 2022-07-19 17:24  watasky  阅读(60)  评论(0)    收藏  举报