雪花
题意:
根据雪花六个角的长度判断两朵雪花是否相同。
思路:
属于hash表内容,根据值域建立一个一样大小的数组进行映射查找,这是hash表的关键,比如本题就可以用长度的和与乘积作为hash的规则,用这个值来归类这些雪花,如果hash值相同,再将两片雪花做精细化比对顺序是否相同。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn = 1e6+10;
const int mod = 99991;
int head[maxn],nxt[maxn],snow[maxn][6];
int n,tot;
int Hash(int *a) {//产生hash值
int sum = 0,mul = 1;
for(int i=0;i<6;i++) {
sum = (sum+a[i])%mod;
mul = (ll)mul*a[i]%mod;
}
return (sum+mul)%mod;
}
bool equal(int *a,int *b) {//看是否循环同构
for(int i=0;i<6;i++) {
for(int j=0;j<6;j++) {
bool flag = true;
for(int k=0;k<6;k++) {//正着循环一遍看是否相同
if(a[(i+k)%6] != b[(j+k)%6]) {
flag = false;
}
}
if(flag) return true;
flag = true;
for(int k=0;k<6;k++) {//再逆着判断一波
if(a[(i+k)%6] != b[(j-k+6)%6]) {
flag = false;
}
}
if(flag) return true;
}
return false;
}
}
bool insert(int *a) {
int val = Hash(a);//获取hash值
for(int i=head[val];i;i = nxt[i]) {//遍历相同hash值的雪花
if(equal(snow[i],a)) return true;//如果相等直接返回true
}
++tot;//类似前向星存边
memcpy(snow[tot],a,6*sizeof(int));
nxt[tot] = head[val];
head[val] = tot;
return false;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) {
int a[10];
for(int j=0;j<6;j++) cin>>a[j];
if(insert(a)) {
cout<<"Twin snowflakes found."<<endl;
return 0;
}
}
cout<<"No two snowflakes are alike."<<endl;
}
兔子
题意:
兔子相同与否靠他的DNA序列来区分,即比对指定区域的两端字符是否相等。
思路:
本题属于字符串hash的内容,对于两个字符串比较他们是否相等,如果我们通过遍历比较当比较次数多、字符串长时效率偏低,字符串hash就是将一个字符串映射成一个非负整数,并且冲突的概率几乎为0。取一固定值P,将字符串中的每一个字符用数字代表,那么这个字符串就会变成一个P进制的数,当我们将P取131或13331这类数时冲突概率较低。所以我们可以先O(n)预处理出字符串所有前缀的hash值,再O(1)查询任意字串的hash值(类似前缀和内味)。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
char s[maxn];
int f[maxn],p[maxn];
int main()
{
scanf("%s",s+1);
int n;
scanf("%d",&n);
p[0] = 1;
int len = strlen(s+1);
for(int i=1;i<=len;i++) {
f[i] = f[i-1]*131+s[i]-'a'+1;
p[i] = p[i-1]*131;
}
for(int i=1;i<=n;i++) {
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(f[r1]-f[l1-1]*p[r1-l1+1] == f[r2]-f[l2-1]*p[r2-l2+1]) {
cout<<"Yes\n";
} else {
cout<<"No\n";
}
}
}