[Luogu P3454] [BZOJ 1100] [POI2007] OSI-Axes of Symmetry

16 篇文章 0 订阅
4 篇文章 0 订阅
洛谷传送门
BZOJ传送门

题目大意

给你一个多边形(不保证是凸的), 要求求出其对称轴数量。

输入输出格式

输入格式

第一行一个整数 T T , 表示有T组数据。

对于每组数据, 第一行一个整数 N N , 表示有N个顶点。

一下 N+1 N + 1 行, 每行两个整数 xi,yi x i , y i ,表示多边形上一个点的坐标。坐标按顺时针方向给出,保证是多边形上的一个顶点(即任意连续三个点不共线)。

输出格式

一共 T T 行,每行一个整数表示多边形的对称轴数量。

输入输出样例

输入样例#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

数据范围

1T10,3N100000

解题分析

几何直接搞不是很好办, 我们将边、角哈希一下变成序列, 然后就成了一个找回文长度 N×2 ≥ N × 2 的回文串个数的字符串题目了…

注意到这是一个环上的问题, 所以要将序列复制一份接在后面。

一开始写了个假的 Manacher M a n a c h e r 结果还能得 70 70 分…

代码如下:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 500050
#define gc getchar()
#define db double
#define EPS 1e-5
#define MOD 1000000007
bool neg;
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    W (!isdigit(c)) 
    {if(c == '-') neg = true; c = gc;}
    W (isdigit(c))
    x = (x << 3) + (x << 1) + c - 48, c = gc;
    if(neg) neg = false, x = -x;
}
int seq[MX << 2];
int ans[MX << 3], cnt;
struct Pt
{int x, y;}pt[MX];
IN int operator * (const Pt &x, const Pt &y)
{return (1ll * (x.x * y.y - x.y * y.x) % MOD + MOD) % MOD;}
IN Pt operator - (const Pt &x, const Pt &y)
{return {x.x - y.x, x.y - y.y};}
int T, dot, tot;
IN int dis(const Pt &x, const Pt &y)
{return 1ll * ((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y)) % MOD;}
IN int getang(const int &lef)//直接返回叉积也行, double太慢
{return 1ll * ((pt[lef] - pt[lef + 1]) * (pt[lef + 2] - pt[lef + 1])) % MOD;}
void Manacher_init()
{
    int bd = dot << 1, tar = dot - 1;
    seq[tot = 0] = -999;
    R int mid = 0, pos = 0; bd = dot << 1;
    for (R int i = 1; i <= bd; ++i)
    {
        if(i < pos) ans[i] = std::min(pos - i, ans[2 * mid - i]);
        else ans[i] = 1;
        W (seq[i - ans[i]] == seq[i + ans[i]]) ++ans[i];
        if(pos < i + ans[i]) pos = i + ans[i], mid = i;
        if(ans[i] - 1 > tar) ++tot;
    }
}
int main(void)
{
    in(T); int bd, step;
    W (T--)
    {
        in(dot);
        for (R int i = 1; i <= dot; ++i)
        in(pt[i].x), in(pt[i].y);
        pt[dot + 1] = pt[1], pt[dot + 2] = pt[2];
        for (R int i = 1; i <= dot; ++i)
        {
            seq[(i << 1) - 1] = dis(pt[i], pt[i + 1]);
            seq[i << 1] = getang(i);
        } bd = dot << 2; step = dot << 1;
        for (R int i = dot << 1 | 1; i <= bd; ++i) seq[i] = seq[i - step];
        Manacher_init();
        printf("%d\n", tot);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值