CF1147B Chladni Figure
题意
给你一个 \(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;
}