码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1100 对称轴osi (回文串)

时间:2016-09-06 22:38:21      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

链接: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 (回文串)

标签:

原文地址:http://www.cnblogs.com/XieWeida/p/5847337.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!