【BZOJ1100】【POI2007】对称轴osi

【Description】

  FGD小朋友——一个闻名遐迩的年轻数学家——有一个小MM,yours。FGD小朋友非常喜欢他的MM,所以他很乐意帮助他的MM做数学作业。但是,就像所有科学的容器一样,FGD的大脑拒绝不停地重复思考同样的问题。不幸的是,yours是一个十分用功的学生,所以她不停地让FGD帮助她检查她的作业。一个阳光明媚的周末,yours的数学老师布置了非常多的寻找多边形的对称轴的题,足够她做相当长的一段时间了。在此之前FGD已经决定去海边度过这个难得的假期,不过他还是觉得应该帮助他的MM对付可爱的数学作业。很快地,他找到了解决方案,最好写一个程序来帮助yours检查她的数学作业。因为FGD并非一个计算机科学家,所以他找到了他的好朋友你,请你帮助他完成这个任务。请写一个程序:读入多边形的描述计算出每个多边形的对称轴数将计算的结果输出


【Input】

  输入的第一行包含一个正整数t(1<=t<=10),为多边形的边数。接下来,为t个多边形的描述,每个描述的第一行为一个正整数n(3<=n<=100000),表示了多边形的点数。然后在后面n行每行两个整数x和y(?100000000<=x, y<=100000000),依次表示多边形的顶点坐标。多边形不一定是凸的,但是不自交——任何两条边都只有最多一个公共点——他们的公共端点。此外,没有两条连续的边平行。


【Output】

  你的程序应该输出正好t行,第k行包含了一个整数nk——表示第k个多边形有多少个对称轴。


【Sample Input】

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

【Sample Output】

4
2

【Hint】

  


【Solution】

  没想到对称轴可以用KMP求,看了题解才知道QAQ。用长度和有向面积(即角度)表示多边形,从1号点绕到n号点一圈。这样如果从某个顶点(或边)向两个方向扩展都是相同的(即出现回文串),那么这个顶角的角平分线(或边的中垂线)即为对称轴。比较是否相同时用KMP统计即可。
  
  代码如下:

/**************************************************************
    Problem: 1100
    User: llgyc
    Language: Pascal
    Result: Accepted
    Time:4844 ms
    Memory:15868 kb
****************************************************************/

const maxn = 400400; inf = maxlongint shr 1;
type point = record x,y:int64; end;
operator  - (a,b:point) c:point; begin c.x:=a.x-b.x; c.y:=a.y-b.y; end;
function len2(a:point):int64; begin exit(a.x*a.x+a.y*a.y); end;
function cross(a,b:point):int64; begin exit(a.x*b.y-a.y*b.x); end;
var t,n,i,j,ans:longint;
    p:array[0..maxn] of point;
    a,template,pre:array[0..maxn] of int64;//a为母串,template为模式串,pre为KMP所用函数
begin
  readln(t);
  while (t>0) do begin
    dec(t); readln(n); fillchar(a,sizeof(a),0); fillchar(template,sizeof(template),0);
    for i:=1 to n do readln(p[i].x,p[i].y); p[0]:=p[n]; p[n+1]:=p[1];
    for i:=1 to n do begin
      a[i<<1-1]:=len2(p[i]-p[i-1]);
      a[i<<1]:=cross(p[i-1]-p[i],p[i+1]-p[i]);
    end;
    n:=n<<1;
    for i:=1 to n do begin template[n-i+1]:=a[i]; a[n+i]:=a[i]; end; 
    //KMP统计对称轴数
    ans:=0; j:=0;
    for i:=2 to n do begin
      while (j<>0) and (template[i]<>template[j+1]) do j:=pre[j];
      if template[i]=template[j+1] then inc(j);
      pre[i]:=j;
    end;
    j:=0;
    for i:=1 to n<<1 do begin
      while (j<>0) and (a[i]<>template[j+1]) do j:=pre[j];
      if a[i]=template[j+1] then inc(j);
      if j=n then begin
        inc(ans); j:=pre[j];
      end;
    end;
    writeln(ans);
  end;
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值