题面

给定一个多边形,求对称轴数量。

分析

初看这似乎是一道计算几何的题目,但是如果暴力枚举对称轴,再去判断对称轴两边的边和角是否相等,时间复杂度为\(O(n^2)\),显然会TLE

问题转换

顺时针转一圈,将角和边的值连在一起就得到了一个环

假如有一个边长为1的三角形,则它的角和边序列应该是:$ 1,60°,1,60°,1,60° $,围成一个环(角为环上的边,边为环上的结点)之后就

变成了:

将1记为a,60°记为b,则环变为:

而对称轴会把这些点分成两部分,且两部分完全一样,对应到序列上就是:断开环上的某一条边,且连

成的序列是回文的

环的处理

对于环上的回文问题,我们不好处理。一种常见的处理方法是选择任意一个位置断开,将序列复制成

为2n长度的链

然后我们在这条链上找长度为n的回文串

找回文串

如何找回文串?Manacher算法是一种很有效的方法,但KMP的使用范围更广。先选择任意一个位置断开,记该序列为S0,再复制一遍得到序列S,将S0反过来得到串T,求S中有多少个位置和T匹配即可

时间复杂度\(O(n)\)

一些细节
  • 如何处理边和角? 边直接用长度表示(注意不必要开方,直接用长度的平方算,大量计算根号会导致TLE),而角由于考虑到图形不一定是凸多边形,采用叉积的方法记录角度,而不是点积。这里运用了叉积的性质:两向量夹角小于180°为正值,夹角大于180°为负值
  • 边和角都用long long 存储,不必用double
  • 序列S的长度为4n,序列T的长度为2n,数组不要开小了

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
using namespace std;
inline void qread(int &x) {
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
} int n;
int T;
struct point {//点
long long x;
long long y;
point() { }
point(long long xx,long long yy) {
x=xx;
y=yy;
}
friend point operator +(point a,point b) {
return point(a.x+b.x,a.y+b.y);
}
friend point operator -(point a,point b) {
return point(a.x-b.x,a.y-b.y);
}
} a[maxn];
typedef point vector;//在程序实现上,点和向量没有区别
long long dot(vector a,vector b) {//点积
return a.x*b.x+a.y*b.y;
}
long long cross(vector a,vector b) {//叉积
return a.x*b.y-a.y*b.x;
} long long dist(point a,point b) {//计算两点间距离
vector v=a-b;
return dot(v,v);
} long long work_edge(int x) {//逐一处理多边形的边,注意编号为n的点下一个点是1
int y=x+1;
if(y>n) y=1;
return dist(a[x],a[y]);
}
long long work_ang(int x) {//处理角,同样注意编号为n的点下一个点是1
int y=x+1,z=x+2;
if(y>n) y=y%n;
if(z>n) z=z%n;
return cross(a[y]-a[x],a[z]-a[y]);
}
long long edge[maxn];
long long ang[maxn];
long long tmp[maxn];
int s[maxn*4];
int t[maxn*2]; int next[maxn*4];
int f[maxn*4];
int KMP(int *a,int n,int *b,int m) {//KMP模板
next[1]=0;
for(int i=2,j=0; i<=n; i++) {
while(j>0&&a[i]!=a[j+1]) j=next[j];
if(a[i]==a[j+1]) j++;
next[i]=j;
}
for(int i=2,j=0; i<=m; i++) {
while(j>0&&b[i]!=a[j+1]) j=next[j];
if(b[i]==a[j+1]) j++;
f[i]=j;
}
int cnt=0;
for(int i=1; i<=m; i++) {
if(f[i]==n) cnt++;
}
return cnt;
}
int main() {
int x,y;
qread(T);
while(T--) {
qread(n);
for(int i=1; i<=n; i++) {
qread(x);
qread(y);
a[i].x=x;
a[i].y=y;
}
for(int i=1; i<=n; i++) {
edge[i]=work_edge(i);
ang[i]=work_ang(i);
}
int newn=0;
int newm=0;
for(int i=1; i<=n; i++) {//由于计算的角是第i与i+1条边之间的夹角,所以先加入边,再加入角
s[++newn]=edge[i];
s[++newn]=ang[i];
}
for(int i=1; i<=n; i++) {
s[++newn]=edge[i];
s[++newn]=ang[i];
}
for(int i=n*2; i>=1; i--) {
t[++newm]=s[i];
}
printf("%d\n",KMP(t,newm,s,newn));
}
}

BZOJ 1100 &&luogu 3454(计算几何+KMP)的更多相关文章

  1. [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)

    [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表) 题面 Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段 ...

  2. BZOJ 3052/Luogu P4074 [wc2013]糖果公园 (树上带修莫队)

    题面 中文题面,难得解释了 BZOJ传送门 Luogu传送门 分析 树上带修莫队板子题... 开始没给分块大小赋初值T了好一会... CODE #include <bits/stdc++.h&g ...

  3. BZOJ 3931 / Luogu P3171 [CQOI2015]网络吞吐量 (最大流板题)

    题面 中文题目,不解释: BZOJ传送门 Luogu传送门 分析 这题建图是显然的,拆点后iii和i′i'i′连容量为吞吐量的边,根据题目要求,111和nnn的吞吐量看作∞\infty∞. 然后用di ...

  4. BZOJ 3894 / Luogu P4313 文理分科 (拆点最小割)

    题面 中文题面- BZOJ 传送门 Luogu 传送门 分析 这道题类似于BZOJ 3774 最优选择,然后这里有一篇博客写的很好- Today_Blue_Rainbow's Blog 应该看懂了吧- ...

  5. BZOJ 2039 / Luogu P1791 [2009国家集训队]employ人员雇佣 (最小割)

    题面 BZOJ传送门 Luogu传送门 分析 考虑如何最小割建图,因为这仍然是二元关系,我们可以通过解方程来确定怎么建图,具体参考论文 <<浅析一类最小割问题 湖南师大附中 彭天翼> ...

  6. BZOJ 2127 / Luogu P1646 [国家集训队]happiness (最小割)

    题面 BZOJ传送门 Luogu传送门 分析 这道题又出现了二元关系,于是我们只需要解方程确定怎么连边就行了 假设跟SSS分在一块是选文科,跟TTT分在一块是选理科,先加上所有的收益,再来考虑如何让需 ...

  7. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  8. [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)

    [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...

  9. BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)

    数组开小毁一生-- 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2085 这题在洛谷上有个条件是"互不包含",其实 ...

随机推荐

  1. 【LuoguP3241】[HNOI2015] 开店

    题目链接 题意 给出一棵边带权的树,多次在线询问一个点到一个区间内的点的距离和. Sol 分块过不了的 一个 trick ,都知道要算两点之间距离可以拆成到根的距离和他们的 LCA 到根的距离 ,其实 ...

  2. python+selenium实现经京东登录+购物+支付

    import json from time import sleep from selenium import webdriver import chardet from selenium.webdr ...

  3. python学习_day1

    简单的输入与输出 python3.x输入 用内置函数input(),返回的数据类型是string,输出用print() 查看数据类型 用type方法 例如 a = int(input('请输入:')) ...

  4. RPA走专有云还是公共云?阿里云RPA公共云给出了这样几组数据…

    自从近年国外UIPATH.AUTOMATION ANYWHERE.BLUE PRISM等RPA企业的崛起,Robotic Process Automation(RPA)走进了人们视野.它以节省成本.提 ...

  5. Java——开发环境配置

    [1]JDK的安装与卸载 (1)卸载程序         控制面板--添加或删除程序--J2SE Development Kit和J2SE Runtime Envioroment--删除 (2)安装程 ...

  6. sh_03_注释

    sh_03_注释 # 这是第一个注释 print("hello hello") """ 这是一个多行注释 .... .... .... 注释结束了 & ...

  7. CG-CTF | 密码重置2

    跟则提示走,美滋滋: 1.找到邮箱: 2.下载备份: 3.PHP弱类型,string与int用的是“==” ........这一行是省略的代码........ if(!empty($token)&am ...

  8. [CSP-S模拟测试]:简单的操作(二分图+图的直径)

    题目描述 从前有个包含$n$个点,$m$条边,无自环和重边的无向图. 对于两个没有直接连边的点$u,v$,你可以将它们合并.具体来说,你可以删除$u,v$及所有以它们作为端点的边,然后加入一个新点$x ...

  9. IIS知识点总结

    一.命令行启动IIS Express 转自:https://www.cnblogs.com/cby-love/p/7102847.html 我们在调试WEB程序的时候可以把本地web程序挂载到本地II ...

  10. CSAR——Channel-wise and Spatial Feature Modulation Network for Single Image Super-Resolution

    1. 摘要 CNN 中的特征包含着不同类型的信息,它们对图像重建的贡献也不一样.然而,现在的大多数 CNN 模型却缺少对不同信息的辨别能力,因此也就限制了模型的表示容量. 另一方面,随着网络的加深,来 ...