BZOJ1100: [POI2007]对称轴osi

来源:互联网 发布:施瓦辛格健身全书淘宝 编辑:程序博客网 时间:2024/04/30 03:53

多组数据清空一定要注意…

一眼感觉是计算几何题…然后不会做….
结果居然是字符串题….

如果我们能将一个多边形表示成一个字符串的话,对称就变成了回文
我们用边长代表这条边,用两条邻边的叉积代表这个点(因为叉积就是有向面积)
然后将这个数字序列复制一份到后面
找所有长度>2*n的回文串
最后答案要/2,因为每个对称轴会被算两次

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int maxn = 410000;int n,m;ll xi[maxn],yi[maxn];ll sqr(const ll x){return x*x;}ll cal(const int x){    int y=x-1; if(!y) y=n;    return sqr(xi[x]-xi[y])+sqr(yi[x]-yi[y]);}ll cal2(const int x){    int y=x+1,z=x-1; if(y>n) y=1; if(!z) z=n;    ll x1=xi[x]-xi[z],y1=yi[x]-yi[z];    ll x2=xi[y]-xi[z],y2=yi[y]-yi[z];    return x1*y2-x2*y1;}ll s[maxn];int r[maxn],id,mx;int main(){    int tcase; scanf("%d",&tcase);    while(tcase--)    {        scanf("%d",&n);        for(int i=1;i<=n;i++) scanf("%lld%lld",&xi[i],&yi[i]);        int len=0; s[0]=LLONG_MAX;        for(int i=1;i<=n;i++)            s[++len]=cal(i),s[++len]=cal2(i);        for(int i=1;i<=len;i++) s[len+i]=s[i];        len<<=1;        s[++len]=LLONG_MIN;        int ans=0; id=mx=0;        for(int i=1;i<len;i++)        {            r[i]=0;            if(mx>i) r[i]=min(mx-i,r[2*id-i]);            while(s[i+r[i]]==s[i-r[i]]) r[i]++;            if(i+r[i]>mx) mx=i+r[i],id=i;            if(r[i]>n) ans++;        }        printf("%d\n",ans>>1);    }    return 0;}