写在前面
第一次写题解,多多包涵qwq
如果有任何问题欢迎评论区留言。
题目大意
给出一些雪花,用一个长度为6的序列表示。
称两片雪花一样当且仅当:从某一个角开始顺时针或者逆时针数得到序列一样。
问给出的雪花中有没有一样的。
数据范围
$1≤n≤100000$
思路
显然是hash。但是从每一个角都存一遍不大可能。所以考虑对整个序列求和求积,然后对一个大质数取模得到hash值。
存储上可以采用邻接表。
(我一开始质数直接上了998244353,后来想到我的head数组根本不可能开这么大……脑子抽了)
(所以这个质数是网上随便找了个质数表选的emmm)
感觉网上直接排序然后字符串hash的有点问题,不过据说可以水过。所以还是写了lyd书上的做法。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10,P=92083;
int n,tot,snow[N][6],head[N],nxt[N],tmp[6];
int get_hash( int *a ) //对雪花求和求积,作为hash值
{
int res1=0,res2=0;
for ( int i=0; i<6; i++ )
res1=(res1+a[i])%P,res2=(ll)res2*a[i]%P;
return (res1+res2)%P;
}
bool check( int *a,int *b ) //判断两片雪花是否相同
{
for ( int i=0; i<6; i++ )
for ( int j=0; j<6; j++ )
{
bool flag=1;
for ( int k=0; k<6; k++ ) //两个雪花方向上相同和相反都判一遍
if ( a[(i+k)%6]!=b[(j+k)%6] ) flag=0;
if ( flag ) return 1;
flag=1;
for ( int k=0; k<6; k++ )
if ( a[(i+k)%6]!=b[(j-k)%6] ) flag=0;
if ( flag ) return 1;
}
return 0;
}
bool insert( int *a ) //把新的雪花插入hash表中
{
int hval=get_hash(a);
for ( int i=head[hval]; i; i=nxt[i] ) //判重
if ( check(snow[i],a) ) return 1;
tot++;
for ( int i=0; i<6; i++ )
snow[tot][i]=a[i];
nxt[tot]=head[hval]; head[hval]=tot; //邻接表
return 0;
}
int main()
{
scanf( "%d",&n );
while ( n-- )
{
for ( int i=0; i<6; i++ )
scanf( "%d",&tmp[i] );
if ( insert(tmp) ) { printf( "Twin snowflakes found.\n" ); return 0; }
}
printf( "No two snowflakes are alike." );
}
res2初始化为1,不然就没用了
res2应该置1
你的初始化把res2设成了0,那后面的关于res2的运算就没有意义了吧
check函数外层i需要循环吗,是不是多余的,只要内层转一周不就行了?
事实证明,确实多余,另一个问题是check函数中判断反向序列中 b[(j-k)%6]模出来的数可能为负数,不知道为啥不报错只要改成b[6+(j-k)%6] 即可把外层循环去掉。亲测ac
(j-k)%6这也有问题 你下标都要变成负数了
少了个+6,应该是(j-k+6)%6
👀