Loading

SP4354 【TWINSNOW - Snowflakes】

这题可以哈希。

可以按照普通的哈希表写,但是插入的时间复杂度比较大还可能被卡单模数哈希。

考虑将每个雪花特征和对于某一个质数取模的余数分类,对于每一类中的数用循环 \(O(n^2)\) 判断 。质数取的大一些就可以减小每一类数的个数,从而保证了复杂度。

关于判断,可以考虑暴力打表,反正没几种情况,而且类似循环展开的还能减小常数。


bool check(int x,int y) {
	for(rint i=0;i<6;++i) {
		if(a[x][0]==a[y][i]&&a[x][1]==a[y][(i+1)%6]
		 &&a[x][2]==a[y][(i+2)%6]&&a[x][3]==a[y][(i+3)%6]
		 &&a[x][4]==a[y][(i+4)%6]&&a[x][5]==a[y][(i+5)%6])return 1;//顺时针
		if(a[x][0]==a[y][i]&&a[x][1]==a[y][(i+5)%6]
		 &&a[x][2]==a[y][(i+4)%6]&&a[x][3]==a[y][(i+3)%6]
		 &&a[x][4]==a[y][(i+2)%6]&&a[x][5]==a[y][(i+1)%6])return 1;//逆时针
	}
	return 0;
}

关于取什么模数好:
尽量把每个雪花分散开,所以取 \(n\) 左右。我取了99991,珂以通过.但是很显然可以卡成 \(O(n^2)\)。。。

还有一种方法,就是随机一个模数出来,这样就几乎不可能卡了。有一种方法(自己yy的,可能有更好的方法):先随机一个在指定范围内的数,然后判断是否为质数。不是就加一接着判断。由于质数比较密集,复杂度可以保证。

这部分的代码大概长这样


	srand(time(0));
	mod=rand()*3+20000;
	while(mod<90000||mod>100000)mod=rand()*3+20000;
	while(!isprime(mod))++mod;
    

由于区间跨度是10000,有3333种rand到的数可以在这个区间,rand的值域是32768,概率大概是 \(\dfrac{1}{10}\) ,很快就可以rand到区间内。

这种随机模数的方法550ms,第4页。直接取99991是460ms,第3页,跑的应该不算慢了,而且码量不大,没压行60行不到。

#include<cstdio>
#include<cctype>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
#define rint register int
typedef long long LL;
inline int rd(){
   int x=0,f=1;
   char ch=getchar();
   while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
   while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
   return x*f;
}
int mod;
const int N=120010;
int a[N][7],n;
vector<int>v[N];
bool check(int x,int y) {
	for(rint i=0;i<6;++i) {
		if(a[x][0]==a[y][i]&&a[x][1]==a[y][(i+1)%6]
		 &&a[x][2]==a[y][(i+2)%6]&&a[x][3]==a[y][(i+3)%6]
		 &&a[x][4]==a[y][(i+4)%6]&&a[x][5]==a[y][(i+5)%6])return 1;
		if(a[x][0]==a[y][i]&&a[x][1]==a[y][(i+5)%6]
		 &&a[x][2]==a[y][(i+4)%6]&&a[x][3]==a[y][(i+3)%6]
		 &&a[x][4]==a[y][(i+2)%6]&&a[x][5]==a[y][(i+1)%6])return 1;
	}
	return 0;
}
bool isprime(int n){
	if(n==1)return false;
	if(n==2||n==3||n==5)return true;
	if(n%6!=1&&n%6!=5)return false;
	for(int i=5,mx=sqrt(n);i<=mx;++i)
	if((n%i==0)||(n%(i+2)==0))return false;
	return true;
}
int main() {
	srand(time(0));
	mod=rand()*3+20000;
	while(mod<90000||mod>100000)mod=rand()*3+20000;
	while(!isprime(mod))++mod;
	//mod=99991; 
	n=rd();
	for(rint i=0;i<n;++i)
		for(rint j=0;j<6;++j)
			a[i][j]=rd();
	long long sum;
	for(rint i=0;i<n;++i) {
		sum=0;
		for(rint j=0;j<6;++j)sum+=a[i][j];
		sum%=mod;
		for(rint j=0;j<v[sum].size();++j)
			if(check(i,v[sum][j]))return puts("Twin snowflakes found."),0;
		v[sum].push_back(i);
	}
	return puts("No two snowflakes are alike."),0;
}
posted @ 2020-05-19 18:07  zzctommy  阅读(162)  评论(0编辑  收藏  举报