CF1147B Chladni Figure

洛谷传送门 CF传送门

题意

给你一个 \(n\) 个点的图,其中有 \(m\) 条线段。求该图形是否为旋转对称图形。

Solution

我们设旋转 \(x\) 个点可以和原图形重合,那么 \(k\cdot x\) 个点也可以

反过来,已知旋转一圈就是原图形,此时旋转了 \(n\) 个点,我们只要找到一个 \(n\) 的因子满足旋转后和原图形重合即可。

那么我们枚举 \(n\) 的因子和每一位旋转后的情况就好了

判断时设此时枚举到 \(d(d|n)\) 和第 \(i\) 位,只要判断 \(i,i+d\) 所含的线段数量是否相等和每一条线段是否都对应。

小剪枝:枚举每一位的过程中如果出现不相等的情况可以立即跳出,枚举 \(n\) 的因子的过程中如果出现满足答案的情况就立即跳出。

注意:输入线段的两个端点 \(u,v\) 时,是有两条线段的,一条是 \(v-u\) ,一条是 \(u-v+n\) ,记得都储存

Code

#include<bits/stdc++.h>

using namespace std;
const int N=1e5+10;
vector<int> d,p[N];
int n,m,flag=1;

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n/2;i++)
        if(n%i==0) d.push_back(i);
    for(int i=1,u,v;i<=m;i++){
        scanf("%d%d",&u,&v);
        if(u>v) swap(u,v);
        p[u].push_back(v-u);
        p[v].push_back((n+u-v-1)%n+1);
    }
    for(int i=1;i<=n;i++)
        sort(p[i].begin(),p[i].end());
    for(int i=0;i<d.size();i++){
        flag=1;
        int now=d[i];
        for(int j=1;j<=n;j++){
            if(p[j].size()!=p[(j+now-1)%n+1].size()){
                flag=0;
                break;
            }
            for(int k=0;k<p[j].size();k++){
                if(p[j][k]!=p[(j+now-1)%n+1][k]){
                    flag=0;
                    break;
                }
            }
            if(flag==0) break;
        }
        if(flag==1) break;
    }
    if(flag==0) puts("No");
    else puts("Yes");
    return 0;
}
posted @ 2020-10-25 14:46  jasony_sam  阅读(138)  评论(0编辑  收藏  举报