[POI2007] OSI-Axes of Symmetry 题解

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

考虑对于一个多边形,其是对称的当且仅当对于若干个边(角),其左右的角与边都是对称的。

考虑如果我们对于内角构造出一种单射,映射为一个整数,将边映射为它的边长,那么我们按照角,边,角,边,……的顺序将他们加入数组中,能构造出一个长度为 \(2n\) 的数组,将这个数组复制一倍,则这个多边形的对称轴数目则为数组的长度为 \(2n+1\) 的回文串的个数的一半。这个可以很简单的用 \(\text{hash,KMP,manacher}\) 求出。

接下来我们考虑如何构造这个单射。题解区大部分用叉乘的方法都能被平行四边形卡掉,我们同时使用点乘和叉乘求出角的 \(\cos\)\(\sin\),这个角的映射值就是 \(1e6 \times (10 \sin + \cos)\)。这样就保证了这是一个单射。

#include<bits/stdc++.h>
using namespace std;
namespace Aurora{ void Main(); }
int main(){ return Aurora::Main(),0; }
namespace Aurora{
    #define ll long long
    #define int long long
    #define debug printf("debug\n")
    const int N=2e5+5,base=1e9+9,mod=1e9+7;
    int T,n,b[N<<2],h1[N<<2],h2[N<<2],p[N<<2];
    struct poi{
        int x,y;
    }a[N];
    int Dis(int i,int j){
        return (a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y);
    }
    int Rag(int i,int j,int k){
        poi A={a[i].x-a[j].x,a[i].y-a[j].y};
        poi B={a[k].x-a[j].x,a[k].y-a[j].y};
        double sn=(A.x*B.y-A.y*B.x)*1.0/(1.0*sqrt(Dis(i,j))*sqrt(Dis(j,k)));
        double cn=(A.x*B.x+A.y*B.y)*1.0/(1.0*sqrt(Dis(i,j))*sqrt(Dis(j,k)));
        double Mjj=(sn*10+cn)*10000;
        int res=Mjj;
        res=(res%mod+mod)%mod;
        return res;
    }
    int Q1(int x,int y){
        return (h1[y]-h1[x-1]*p[y-x+1]%mod+mod)%mod;
    }
    int Q2(int x,int y){
        return (h2[x]-h2[y+1]*p[y-x+1]%mod+mod)%mod;
    }
    void Main(){
        scanf("%lld",&T);
        p[0]=1;
        for(int i=1;i<=N*4-5;i++) p[i]=p[i-1]*base%mod;
        while(T--){
            memset(h1,0,sizeof(h1));
            memset(h2,0,sizeof(h2));
            scanf("%lld",&n);
            for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y);
            a[0]=a[n],a[n+1]=a[1];
            for(int i=1;i<=n;i++){
                b[i*2-1]=Dis(i-1,i);
                b[i*2]=Rag(i-1,i,i+1);
            }
            // for(int i=1;i<=n*2;i++) printf("%lld ",b[i]);
            // puts("");
            for(int i=1;i<=n*2;i++) b[i+n*2]=b[i];
            // for(int i=1;i<=n*4;i++) printf("%lld ",b[i]);
            // puts("");
            for(int i=1;i<=n*4;i++) h1[i]=(h1[i-1]*base+b[i])%mod;
            for(int i=n*4;i>=1;i--) h2[i]=(h2[i+1]*base+b[i])%mod;
            int ans=0;
            for(int i=1;i<=n*2;i++){
                // printf("ID:%lld H1:%lld H2:%lld \n",i,Q1(i,i+n*2),Q2(i,i+n*2));
                if(Q1(i,i+n*2)==Q2(i,i+n*2)){
                    // printf("%lld ",i);
                    ans++;
                }
            }
            // puts("");
            printf("%lld\n",ans/2);
        }        
    }
}

posted @ 2024-07-30 18:48  Aurora_Borealis  阅读(7)  评论(0编辑  收藏  举报