题解 P3454 【[POI2007]OSI-Axes of Symmetry】
xtx1092515503 · · 题解
Manacher做法。
考虑一个多边形的对称轴有什么性质——
明显,如果沿着对称轴的一端把整个环状的多边形裁成一条链,则链上相邻两条边的夹角,必定是回文的。
回文就直接上Manacher啦。
我们把整个多边形断环成链复制三份,然后对着复制完的多边形的所有夹角构成的串跑一遍Manacher。假如发现里面出现了一条长度
注意,因为对称轴会在其与多边形的两个交点处被计算两遍,故最终答案应除以
具体实现时,可以使用叉积判夹角相同,但实际上使用 atan2 暴力算夹角然后用 double 判相同也够用了。
代码:
#include<bits/stdc++.h>
using namespace std;
int T,n;
const double pi=acos(-1);
const double eps=1e-10;
struct Vector{
double x,y;
Vector(double X=0,double Y=0){x=X,y=Y;}
friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
friend Vector operator *(const Vector &u,const double &v){return Vector(u.x*v,u.y*v);}
friend Vector operator /(const Vector &u,const double &v){return Vector(u.x/v,u.y/v);}
friend double operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
friend double operator |(const Vector &u,const Vector &v){return u.x*v.x+u.y*v.y;}//point times
double operator ~()const{return sqrt(x*x+y*y);}//the modulo of a vector
double operator !()const{return atan2(y,x);}//the angle of a vector
void read(){scanf("%lf%lf",&x,&y);}
}p[300100];
int m;
double ang[600100];
int Centre,Rpos,rad[600100];
double FMOD(double ip){
if(ip<0)ip+=2*pi;
if(ip>=2*pi)ip-=2*pi;
return ip;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n),m=0;
for(int i=1;i<=n;i++)p[i].read(),p[n+i]=p[2*n+i]=p[i];
p[0]=p[n],p[3*n+1]=p[1];
ang[++m]=-1;
for(int i=1;i<=3*n;i++){
ang[++m]=FMOD(!(p[i+1]-p[i])-!(p[i]-p[i-1]));
ang[++m]=-1;
}
Centre=Rpos=0;
for(int i=1;i<=m;i++){
rad[i]=(i<Rpos)?min(Rpos-i,rad[Centre*2-i]):1;
while(i+rad[i]<=m&&i-rad[i]>=1)if(fabs(ang[i+rad[i]]-ang[i-rad[i]])<eps)rad[i]++;else break;
if(i+rad[i]>Rpos)Rpos=i+rad[i],Centre=i;
}
int res=0;
for(int i=2*n+1;i<=4*n;i++)res+=(rad[i]>=n);
printf("%d\n",res>>1);
}
return 0;
}