题目
http://poj.org/problem?id=3349
https://www.luogu.org/problemnew/show/SP4354
解题思路
本题我调了很久!!!
这道题的
u
s
s
i
g
n
e
d
(
l
o
n
g
l
o
n
g
)
ussigned\ (long\ long)
ussigned (long long)很烦,不过它们有自然溢出的功能。
因为顺时针和逆时针都可以,所以只需将原串在前后复制两遍,然后做两遍最小表示法,求出最小同构串,
h
a
s
h
hash
hash一下即可。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
const unsigned inf=160001;
unsigned long long h[inf];
unsigned a[21],n;
unsigned in(){
unsigned ans=0; char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans;
}
int findd(unsigned long long k)//hash哈希表
{
unsigned g=k%inf,i=0;
while (i<inf&&h[(g+i)%inf]&&h[(g+i)%inf]!=k) i++;
return (g+i)%inf;
}
bool hash(unsigned ans1,unsigned ans2)
{
bool b=0; unsigned i,summ,ans=ans1; unsigned long long sum=0;
for (i=0;i<6&&a[ans1+i]==a[ans2-i];i++);//求最小同构串
if (a[ans1+i]>a[ans2-i]) {ans=ans2; b=1;}
if (b) {//累求hash值
for (unsigned j=ans;j>ans-6;j--)
sum=sum*13131+a[j];
} else {
for (unsigned j=ans;j<ans+6;j++)
sum=sum*13131+a[j];
}
if (h[(summ=findd(sum))]==sum) return 1;
h[summ]=sum; return 0;
}
int main()
{
n=in();
while (n--)
{
for (unsigned i=7;i<=12;i++)
scanf("%d",&a[i]),a[i-6]=a[i+6]=a[i];
int ii=7,jj=8,kk;
while (ii<=12&&jj<=12)//顺时针
{
kk=0; while (kk<=6&&a[ii+kk]==a[jj+kk])kk++;
if (kk==6) break;
if (a[ii+kk]>a[jj+kk]) {ii=ii+kk+1; if (ii==jj) ii++;}
else {jj=jj+kk+1; if (ii==jj) jj++;}
}
unsigned ans1=min(ii,jj); ii=12,jj=11;
while (ii>=7&&jj>=7)//逆时针
{
kk=0; while (kk<=6&&a[ii-kk]==a[jj-kk])kk++;
if (kk==6) break;
if (a[ii-kk]>a[jj-kk]) {ii=ii-kk-1; if (ii==jj) ii--;}
else {jj=jj-kk-1; if (ii==jj) jj--;}
}
unsigned ans2=max(ii,jj);
if (hash(ans1,ans2)) {
printf("Twin snowflakes found."); return 0;
}
}
printf("No two snowflakes are alike.");
}