zoukankan      html  css  js  c++  java
  • 题解-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
    ",ans>>1);
    }
    
    int main(){
    	int T;read(T);
    	while(T--)init(),work();
    	return 0;
    }
    
  • 相关阅读:
    15 鼠标事件
    09 属性操作
    06 DOM操作之插入节点
    03 如何处理多个库$冲突的问题
    01 jquery引入
    08 千千音乐盒实现全选和反选
    03 衣服相册切换效果
    02 显示和隐藏图片
    01 图片切换
    派生
  • 原文地址:https://www.cnblogs.com/penth/p/10241641.html
Copyright © 2011-2022 走看看