BZOJ1100 : [POI2007]对称轴osi

本文介绍了一种利用Manacher算法检测多边形对称轴的方法,通过将多边形转换为特定序列并寻找回文串来高效确定对称轴的位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

将多边形转化为如下的环:

1到2的边,角2,2到3的边,角3,...,n-1到n的边,角n,n到1的边,角1

然后枚举对称轴,如果i是对称轴,那么[i-n,i+n]是一个回文串

用Manacher算法实现即可。

时间复杂度$O(n)$。

 

#include<cstdio>
#define N 100010
typedef long long ll;
int T,n,i,r,p,f[N<<2],ans;
struct P{
  int x,y;
  P(){x=y=0;}
  P(int _x,int _y){x=_x,y=_y;}
  inline P operator-(P b){return P(x-b.x,y-b.y);}
}a[N];
inline ll sqr(ll x){return x*x;}
inline ll dis(P a,P b){return sqr(a.x-b.x)+sqr(a.y-b.y);}
inline ll cross(P a,P b){return (ll)a.x*b.y-(ll)a.y*b.x;}
struct Q{
  ll x;int y;
  Q(){x=y=0;}
  Q(ll _x,int _y){x=_x,y=_y;}
  inline bool operator==(Q b){return x==b.x&&y==b.y;}
}b[N<<2];
inline int min(int a,int b){return a<b?a:b;}
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
  if(c!='-')a=c-'0';else f=1;
  while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
  if(f)a=-a;
}
int main(){
  for(read(T);T--;printf("%d\n",ans>>1)){
    read(n);
    for(i=1;i<=n;i++)read(a[i].x),read(a[i].y);
    a[n+1]=a[1],a[n+2]=a[2];
    for(i=1;i<=n;i++){
      b[i*2-1]=Q(dis(a[i],a[i+1]),1);
      b[i*2]=Q(cross(a[i+1]-a[i],a[i+1]-a[i+2]),2);
    }
    for(i=1;i<=n*2;i++)b[i+n*2]=b[i];
    b[n*4+1]=Q(0,3);
    for(r=p=0,i=1;i<=n*4;i++){
      for(f[i]=r>i?min(r-i,f[p*2-i]):1;b[i-f[i]]==b[i+f[i]];f[i]++);
      if(i+f[i]>r)r=i+f[i],p=i;
    }
    for(ans=0,i=n+1;i<=n*3;i++)if(f[i]>n)ans++;
  }
  return 0;
}

  

转载于:https://www.cnblogs.com/clrs97/p/4610049.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值