BZOJ1100 对称轴osi (回文串)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1100 对称轴osi (回文串)相关的知识,希望对你有一定的参考价值。
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1100
分析:将多边形转化为如下的环:
角度0->0到1的边长->角度1->1到2的边长->...->角度n-1->n-1到0的边长。将其存到s中,再将s复制一遍存到后面。
然后枚举对称轴i,无非在边或顶点上,如果i为对称轴,那么[i-n,i+n]是一个回文串。
用Manacher算法算出以i为对称轴的最长回文串向左或右延伸的最大长度(包括i),当大于n时,说明以i为轴,两侧对应的边长和角度都相等,对称轴计数+1(ps:联想下铁拉门)。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 100000 + 5; 7 8 int x[maxn], y[maxn], s[maxn << 2], p[maxn << 2]; 9 10 inline int dis(const int& a, const int& b) { 11 return (x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]); 12 } 13 14 inline int cross(const int& a, const int& b, const int& c) { 15 return (x[b] - x[a]) * (y[c] - y[a]) - (x[c] - x[a]) * (y[b] - y[a]); 16 } 17 18 int main() { 19 int t; 20 scanf("%d", &t); 21 while (t--) { 22 int n; 23 scanf("%d", &n); 24 for (int i = 0; i < n; i++) scanf("%d%d", &x[i], &y[i]); 25 for (int i = 0; i < n; i++) s[i << 1 | 1] = dis(i, (i + 1) % n); 26 for (int i = 0; i < n; i++) s[i << 1] = cross(i, (i - 1 + n) % n, (i + 1) % n); 27 int all = n << 1; for (int i = 0; i < n; i++) s[all + i] = s[i]; all <<= 1; 28 int ans = 0, mx = 0, id = 0; memset(p, 0, sizeof(p)); 29 for (int i = 0; i < all; i++) { 30 p[i] = mx > i ? min(p[id * 2 - i], mx - i) : 1; 31 while (i - p[i] >= 0 && i + p[i] < all && s[i - p[i]] == s[i + p[i]]) p[i]++; 32 if (i + p[i] > mx) { mx = i + p[i]; id = i; } 33 if (p[i] > n) ans++; 34 } 35 printf("%d\n", ans); 36 } 37 return 0; 38 }
以上是关于BZOJ1100 对称轴osi (回文串)的主要内容,如果未能解决你的问题,请参考以下文章