P8142
题意
由于题面太难理解了,我们形象化一下。
你面前有一个地球仪,用记号笔涂了 \(n\) 个点,告诉你这 \(n\) 个点的经纬度坐标。然后又告诉你另外 \(n\) 个点的经纬度坐标,让你判断可不可以通过转动地球仪,来让他们重合。
分析
首先注意到题目限制,对于给出的经纬度坐标 \((a,b)\),有 \(-90<a<90\)、\(-180<b<180\),这样我们就可以不用考虑类似在极点这样的边界情况。(出题人我谢谢你)
注意到不管怎么转,一个点所在的纬度不会改变,这提示我们对于不同纬度分开考虑,然后再思考如何合并不同的纬度。
首先,对于同一个纬度,最基本的要求是所含点的个数一样。其次,明显可以发现,不管如何转动,经度的差分数组始终是不变的。关注到这一点,我们就考虑如何判断两个差分数组是不是可以经过转动得到的。
事实上,这是判断两个串是否循环同构,我们可以使用最小表示法,也可以使用把其中一个复制一倍,再跑 KMP 就可以简单判断出。
如果两个数组可以转动得到,我们就记录下所有可以使他们重合需要转的角度。再对所有纬度的角度集合判断交集是否为空。
注意到同层的点可能有循环节,这意味着不止有一个角度可以使他们重合,需要全部记下。
注意实现上的一些细节。
-
求交集可以使用
map,也可以用记到数组里,减小常数。 -
浮点数可能有误差,由于最多四位小数,可以转成
int来存。 -
如果你转成
int了,一定不能直接把输入的乘上 \(10000\),这样会发生神秘错误,一定要用快读板子魔改一下来输入。 -
在这道题里,\(-90\) 和 \(270\) 是一样的角度,可以直接把负数加上 \(360\) 避免特判。
剩下的看代码吧。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=4e5+10;
int n,ne[N],Q[N],Q1[N],hh,hh1;
int A[N],B[N];
struct node{
int x,y;
}a[N],b[N];
inline bool cmp(node x,node y){
return x.x==y.x?x.y<y.y:x.x<y.x;
}
char buf[1<<21],*p1=buf,*p2=buf;
inline char gc(){
if(p1==p2) p2=(p1=buf)+fread(buf,1,1<<21,stdin);
return *p1++;
}
inline int read(){
int res=0;
char ch=gc();
bool f=1;
while(ch<'0'||ch>'9'){
if(ch=='-') f=0;
ch=gc();
}
while(ch>='0'&&ch<='9'){
res=(res<<1)+(res<<3)+(ch^48);
ch=gc();
}
if(ch=='.'){
ch=gc();
int cnt=0;
while(ch>='0'&&ch<='9'){
++cnt;
res=(res<<1)+(res<<3)+(ch^48);
ch=gc();
}
while(cnt<4) res*=10,++cnt;
}
else{
res*=10000;
}
return f?res:-res;
}
int main(){
scanf("%d",&n);
for(int i=1,x,y;i<=n;++i){
x=read();y=read();
a[i]=/**/{x,y};
}
for(int i=1,x,y;i<=n;++i){
x=read();y=read();
b[i]=/**/{x,y};
}
sort(a+1,a+1+n,cmp);
sort(b+1,b+1+n,cmp);
int p1=1,tim=0;
bool fi=1;
while(p1<=n){
++tim;
int m=1,ne1=p1,ne2=p1;
A[0]=a[p1].y,B[0]=b[p1].y;
while(ne1<n&&a[ne1].x==a[ne1+1].x) A[m++]=a[++ne1].y;
m=1;
while(ne2<n&&b[ne2].x==b[ne2+1].x) B[m++]=b[++ne2].y;
if(ne1!=ne2||a[p1].x!=b[p1].x){
puts("Different");
return 0;
}
int tmp=A[m-1];
for(int i=m-1;i>0;--i){
A[i]=A[i]-A[i-1];
if(A[i]<0) A[i]=3600000+A[i];
}
A[0]=A[0]-tmp;
if(A[0]<0) A[0]=3600000+A[0];
tmp=B[m-1];
for(int i=m-1;i>0;--i){
B[i]=B[i]-B[i-1];
if(B[i]<0) B[i]=3600000+B[i];
}
B[0]=B[0]-tmp;
if(B[0]<0) B[0]=3600000+B[0];
ne[m+1]=0;
for(int i=2,j=0;i<=m;++i){
while(j&&A[i-1]!=A[j]) j=ne[j];
ne[i]=(A[i-1]==A[j]?++j:j);
}
int i=0,j=1,k=0;
while(i<m&&j<m&&k<m){
if(A[(i+k)%m]==A[(j+k)%m]) ++k;
else{
A[(i+k)%m]<A[(j+k)%m]?j+=k+1:i+=k+1;
if(i==j) ++i;
k=0;
}
}
int bg1=min(i,j);
i=0,j=1,k=0;
while(i<m&&j<m&&k<m){
if(B[(i+k)%m]==B[(j+k)%m]) ++k;
else{
B[(i+k)%m]<B[(j+k)%m]?j+=k+1:i+=k+1;
if(i==j) ++i;
k=0;
}
}
int bg2=min(i,j);
for(int i=0;i<m;++i){
if(A[bg1]!=B[bg2]){
puts("Different");
return 0;
}
bg1=(bg1+1)%m,bg2=(bg2+1)%m;
}
bool hav=0;
tmp=a[p1+bg1].y-b[p1+bg2].y;
if(tmp<0) tmp=3600000+tmp;
hh1=0;
Q1[++hh1]=tmp;
int len=m-ne[m];
if(m%len==0){
for(int i=(bg1+len)%m;i!=bg1;i=(i+len)%m){
tmp=a[p1+i].y-b[p1+bg2].y;
if(tmp<0) tmp=3600000+tmp;
Q1[++hh1]=tmp;
}
}
sort(Q1+1,Q1+1+hh1);
tmp=unique(Q1+1,Q1+1+hh1)-Q1-1;
hh1=tmp;
if(fi){
for(int i=1;i<=hh1;++i) Q[i]=Q1[i];
hh=hh1;
}
else{
int tot=0;
j=1;
for(int i=1;i<=hh1;++i){
while(j<=hh&&Q[j]<Q1[i]) ++j;
if(Q[j]==Q1[i]) Q[++tot]=Q[j],hav=1;
}
hh=tot;
}
if(!fi&&!hav){
puts("Different");
return 0;
}
fi=0;
p1=ne1+1;
}
puts("Same");
return 0;
}

浙公网安备 33010602011771号