题解-POI2007 OSI-Axes of Symmetry

Problem

bzoj1100

题意概要:给定一个简单多边形(不一定凸),求其对称轴数量

数据组数\(\leq 10\),多边形点数\(\leq 10^5\)

Solution

这题算是跨界算法的经jian典dan题目了吧

观察多边形对称的性质,容易发现其本质就是沿着对称轴翻折可以使多边形重合,即两侧一致

进一步发现所有边长和角度相等,可证如果给定固定的角度和边长,只能得到一种图形,所以一旦某点或某边两侧的边长角度对应相等,则一定存在一条对称轴穿过该点或该边

为了快速地得到对应相等的边和角,可以采用按照多边形的输入顺序将边角混合放进序列跑manacher,处理环的话倍增序列即可

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline void read(int&x){
    char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')ob=1,c11=getchar();
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;
}

const int N=1001000;
const double eps=1e-8;

struct vec{
    int x,y;
    inline vec(){}
    inline vec(const int&X,const int&Y):x(X),y(Y){}
    inline void in(){read(x),read(y);}
    friend inline vec operator - (const vec&A,const vec&B) {return vec(A.x-B.x,A.y-B.y);}
    friend inline ll operator * (const vec&A,const vec&B) {return (ll)A.x*B.y-(ll)A.y*B.x;}
    inline double len(){return sqrt((ll)x*x+(ll)y*y);}
}p[N];

struct node{
    int sgn;double v;
    inline node(){}
    inline node(const int&SGN,const double&V):sgn(SGN),v(V){}
    friend inline bool operator == (const node&A,const node&B)
        {return A.sgn==B.sgn and fabs(A.v-B.v)<eps;}
}t[N];

inline double angle(vec A,vec B,vec C){C=C-B,B=B-A;return 1.0*(B*C)/B.len()/C.len();}

int n,f[N],e;

void init(){
    read(n);
    for(int i=1;i<=n;++i)p[i].in();
    p[0]=p[n],p[n+1]=p[1];
    e=0;
    for(int i=1;i<=n;++i){
        t[++e]=node(0,0);
        t[++e]=node(1,angle(p[i-1],p[i],p[i+1]));
        t[++e]=node(0,0);
        t[++e]=node(2,(p[i+1]-p[i]).len());
    }
    for(int i=1;i<=e;++i)t[i+e]=t[i];
    t[e=e<<1|1]=node(0,0);
}

void work(){
    int R=0,ps=0,ans=0;
    for(int i=0;i<=e;++i)f[i]=0;
    for(int i=1;i<=e;++i){
        if(i<R)f[i]=min(f[ps+ps-i],R-i);
        else f[i]=1;
        while(f[i]<i and i+f[i]<=e and t[i+f[i]]==t[i-f[i]])
            ++f[i];
        if(i+f[i]>R)ps=i,R=i+f[i];
        if(f[i]-1>=n+n)++ans;
    }
    printf("%d\n",ans>>1);
}

int main(){
    int T;read(T);
    while(T--)init(),work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/penth/p/10241641.html