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;
}
posted @ 2023-11-12 13:05  mRXxy0o0  阅读(23)  评论(0)    收藏  举报