洛谷P3454 [POI2007]OSI-Axes of Symmetry
? 解题记录 ? ? 洛谷 ? ? 哈希 ? ? Manacher ?    2018-07-11 16:50:30    330    0    0

描述:

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

n <= 1000000 

 

输入输出样例

输入样例#1: 复制
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
输出样例#1: 复制
4
2​​

 

 

 

 

 

 

 

 

 

讲讲这道题的心路历程吧:

这道题虽然有个明显的O(n^2)算法对吧,但是明摆着要O(n)。

于是就开始各种乱搞了……

乱搞1:把边考虑上,取每个边的中点和所有的多边形顶点,求出所有点的平均点(横纵坐标取平均值),因为图形要对称两边的点一定要相等。那么可以O(n)枚举对角线验证过不过平均点。不过这个算法一经提出就被自己卡了:

于是就有了乱搞2:我们再判一下一个点向左向右发出的两条边是不是对称。然后我又把自己卡了:

真是个悲惨的故事!不过这个思维是可以无限延伸的,我们可以一直往两边判断,实际上也就乘个常数,说不准就卡过了呢!

 

下面我们说说正解吧:

先是三个字正解:

 

 

 

 

字符串

 

 

 

 

这是一道字符串……

什么,为什么我想了半天都没看出来这是道字符串???

对呀……我太菜了……

我们考虑把多边形哈希,不过我们哈希的姿势要独特一些:沿用乱搞1,我们把边和角都提出来哈希,边用边长,角就用两条边的向量在模意义下的叉积。这样我们保证了无论图形怎么摆,只要边角哈希值的有序序列一样两个图形就一样。那么要两边对称变成了什么呢?

 

 

 

 

 

 

 

——回文串

 

是的,然后就变成了求环上的长度为n * 2 + 1的回文串个数……这道题没了。

我的字符串修为太低了……

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define sqr(x) (1ll * (x) * (x))
using namespace std;
const int maxn = 1e6 + 5, base = 19260817, P = 1e9 + 7;
int t, n, x[maxn], y[maxn], ag[maxn], grp[maxn << 1], len;

int GetAng(int x1, int y1, int x2, int y2) {
    return ((long long)abs(1ll * x1 * y2 - 1ll * y1 * x2) % P + P) % P;
}

int RL[maxn], ans;
void Manacher(int * s, int len) {
    int Mid = 1, Mr = 1, l, r;
    for(register int i = 1; i <= len; ++i) {
        RL[i] = min(RL[(Mid << 1) - i], Mr - i);
        for(;(l = i - RL[i]) >= 1 && (r = i + RL[i]) <= len; ++RL[i]) {
            if(s[l] != s[r]) {++RL[i]; break;}
        }
        --RL[i];
        if(i + RL[i] > Mr) Mr = i + RL[i], Mid = i;
    }
}

int ch[maxn << 2], cnt;

int main() {
    scanf("%d", &t);
    while(t--) {
        cnt = ch[0] = grp[0] = len = ans = 0;
        scanf("%d", &n);
        for(register int i = 1; i <= n; ++i)
            scanf("%d%d", &x[i], &y[i]);
        x[0] = x[n], y[0] = y[n];
        x[n + 1] = x[1], y[n + 1] = y[1];
        for(register int i = 1; i <= n; ++i)
            ag[i] = GetAng(x[i - 1] - x[i], y[i - 1] - y[i], x[i + 1] - x[i], y[i + 1] - y[i]);
        for(register int i = 1; i <= n; ++i) {
            grp[++grp[0]] = ag[i];
            grp[++grp[0]] = (sqr(x[i + 1] - x[i]) % P + sqr(y[i + 1] - y[i]) % P) % P;
        }
        for(register int i = 1; i <= grp[0]; ++i) {
            grp[i + grp[0]] = grp[i];
        }
        
        grp[0] <<= 1, len = n * 2;
        ch[++cnt] = -1;
        for(register int i = 1; i <= grp[0]; ++i)
            ch[++cnt] = grp[i], ch[++cnt] = -1;
        
        Manacher(ch, cnt);
        for(register int i = 1; i <= cnt; ++i)
            if(RL[i] / 2 >= n) 
                ++ans;
        printf("%d\n", ans / 2);
    }
    return 0;
}

上一篇: Atcoder Code Festival 2017 Exhibition B - Increment and Swap

下一篇: CF#484 Div2 D. Shark

330 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航