这题可以哈希。
可以按照普通的哈希表写,但是插入的时间复杂度比较大还可能被卡单模数哈希。
考虑将每个雪花特征和对于某一个质数取模的余数分类,对于每一类中的数用循环 (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;
}