[BZOJ1100][POI2007]对称轴osi

1100: [POI2007]对称轴osi

Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 716  Solved: 279 [Submit][Status][Discuss]

Description

FGD小朋友——一个闻名遐迩的年轻数学家——有一个小MM,yours。FGD小朋友非常喜欢他的MM,所以他很乐 意帮助他的MM做数学作业。但是,就像所有科学的容器一样,FGD的大脑拒绝不停地重复思考同样的问题。不幸的 是,yours是一个十分用功的学生,所以她不停地让FGD帮助她检查她的作业。一个阳光明媚的周末,yours的数学 老师布置了非常多的寻找多边形的对称轴的题,足够她做相当长的一段时间了。在此之前FGD已经决定去海边度过 这个难得的假期,不过他还是觉得应该帮助他的MM对付可爱的数学作业。很快地,他找到了解决方案,最好写一个 程序来帮助yours检查她的数学作业。因为FGD并非一个计算机科学家,所以他找到了他的好朋友你,请你帮助他完 成这个任务。请写一个程序:读入多边形的描述计算出每个多边形的对称轴数将计算的结果输出

Input

  输入的第一行包含一个正整数t(1<=t<=10),为多边形的边数。接下来,为t个多边形的描述,每个描述的第一 行为一个正整数n(3<=n<=100000),表示了多边形的点数。然后在后面n行每行两个整数x和y(?100000000<=x, y<=1 00000000),依次表示多边形的顶点坐标。多边形不一定是凸的,但是不自交——任何两条边都只有最多一个公共 点——他们的公共端点。此外,没有两条连续的边平行。

Output

  你的程序应该输出正好t行,第k行包含了一个整数nk——表示第k个多边形有多少个对称轴。

Sample Input

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

Sample Output

4
2

HINT

 

乍一看是计算几何,结果是字符串。。。

把边长和角度存起来,然后找最长回文串即可。。。

角度的话会被卡精度,所以用叉积代替

#pragma GCC optimize("O2")
#include <cstdio>
char buf[20000000], *ptr = buf - 1;
inline int readint(){
    int n = 0;
    bool flag = false;
    while(*++ptr < '0' || *ptr > '9') if(*ptr == '-') flag = true;
    while(*ptr <= '9' && *ptr >= '0') n = (n << 1) + (n << 3) + (*ptr++ & 15);
    return flag ? -n : n;
}
template <typename _Tp>
inline _Tp min_(const _Tp &a, const _Tp &b){
    return a < b ? a : b;
}
typedef long long ll;
const int maxn = 100000 + 10;
struct Poi{
    ll x, y;
    Poi(){}
    Poi(ll _x, ll _y): x(_x), y(_y){}
    Poi operator - (const Poi &a){
        return Poi(x - a.x, y - a.y);
    }
}p[maxn];
inline ll sqr(const ll &x){
    return x * x;
}
inline ll dis(const Poi &a, const Poi &b){
    return sqr(a.x - b.x) + sqr(a.y - b.y);
}
inline ll cross(const Poi &a, const Poi &b){
    return a.x * b.y - a.y * b.x;
}
int n;
ll s[maxn * 3];
int r[maxn * 3];
void work(){
    n = readint();
    for(int i = 1; i <= n; i++){
        p[i].x = readint();
        p[i].y = readint();
    }
    p[0] = p[n];
    p[n + 1] = p[1];
    for(int i = 1; i <= n; i++){
        s[i * 2 - 1] = cross(p[i - 1] - p[i], p[i + 1] - p[i]);
        s[i * 2] = dis(p[i], p[i + 1]);
    }
    int len = n + n;
    for(int i = 1; i <= n; i++)
        s[i + len] = s[i];
    len = len + n;
    int mx = 0, id = 0, ans = 0;
    for(int i = 1; i <= len; i++){
        if(mx > i) r[i] = min_(r[2 * id - i], mx - i);
        else r[i] = 1;
        while(i - r[i] > 0 && i + r[i] <= len && s[i - r[i]] == s[i + r[i]]) r[i]++;
        if(r[i] + i > mx){
            mx = r[i] + i;
            id = i;
        }
        if(r[i] > n) ans++;
    }
    printf("%d\n", ans);
}
int main(){
    fread(buf, sizeof(char), sizeof(buf), stdin);
    int T = readint();
    while(T--) work();
    return 0;
}

 

posted @ 2017-10-05 20:45  jzyy  阅读(244)  评论(0编辑  收藏  举报