咸鱼钟大爷
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)Submit Status
钟望大爷刚刚学习了字符串的哈希算法,对于字符串哈希,他使用的哈希函数是hash[i]=(hash[i-1]*p+ASCII(s[i]))%mod;比如对于p = 2,mod = 1000时,hash('ab') = 97 * 2 + 98 = 292;他认为这样的哈希方法是很难发生冲突的。正巧,这个函数被周日天看到了,周日天劈头盖脸的就是一顿批判,然后扬长而去。留下了钟望大爷在原地一脸懵逼。
现在,对于给出的p,mod,钟望大爷希望你能构造出两个不同字符串(字符串长度不能大于1,000,000且只能由小写字母构成),使得他们的哈希值在这个哈希函数中相同。
Input
输入包括2个正整数p,mod。(0 < p < mod <= 1,000,000,000);Output
对于每组数据,输出占2行,输出任意一对满足条件的不同的字符串(字符串长度不能大于1,000,000且只能由小写字母构成)。Sample input and output
Sample Input Sample Output1 2 a
c
Hint
两个字符串的长度可以不同!!!!!
Source
2017 UESTC Training for Search Algorithm & String
My Solution
题意:给出一个p和mod,求出一对哈希冲突的字符串(长度可以不同)
随机化+哈希
随机生成字符串,然后哈希,然后判断f[hashval]是否出现过,如果出现过就找到了哈希冲突的字符串。
如果枚举到MAXN还是没有找到就换一个哈希种子重新找,这里由于oj把ctime禁用了,
所以可以每次定义一个变量,然后用这个变量的地址作为哈希种子。
关于可以使用随机化的原因,请搜索“生日攻击”百科,里面有详细证明。
复杂度 O(n)
#include <iostream>
#include <cstdio>
#include <cstring>
#include<cstdlib>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN = 1e6;
LL p, MOD;
char s[MAXN+8];
inline LL mod(LL x){
return x - x / MOD * MOD;
}
inline int getASCII(int i)
{
s[i] = char(rand()%26 + 'a');
return int(s[i]);
}
map<LL, int> mp;
int main()
{
#ifdef LOCAL
freopen("h.txt", "r", stdin);
//freopen("h.out", "w", stdout);
int T = 4;
while(T--){
#endif // LOCAL
//ios::sync_with_stdio(false); cin.tie(0);
scanf("%lld%lld", &p, &MOD);
bool ans = false;
int i, ind, cnt = 0;
while(true){
if(ans) break;
mp.clear();
LL hashv, last;
cnt+=19;
cnt = max(cnt, 1);
srand(int(&hashv) + cnt);
last = mod(getASCII(0));
mp[last] = 0;
for(i = 1; i < MAXN; i++){
hashv = mod(last*p+getASCII(i));
//printf("%s\n", s);
if(mp.find(hashv) != mp.end()){
s[i+1] = '\0';
printf("%s\n", s);
s[mp[hashv]+1] = '\0';
printf("%s\n", s);
ans = true;
//cout << hashv << " " << hashmap[ind] << endl;
break;
}
last = hashv;
mp[last] = i;
}
}
#ifdef LOCAL
cout << endl;
}
#endif // LOCAL
return 0;
}
Thank you!
------from ProLights