【题目描述】
经过了训练、资金等多方面的准备,处女座终于可以去比赛了!比赛采用codeforces赛制,也就意味着可以插人。现在有一道字符串的题目,处女座在room里看到一个用hash做的,于是决定把它hack掉。这个人的核心代码如下:
const int mod=9983; mul[0]=p; mul[1]=q; mul[2]=r; for (int i=0;i<26;i++) in_dex[i]=i*t+t; int get_hash(char* s)//下标从1开始 { int ans=0,len=strlen(s+1); for (int i=1;i<=len;i++) ans=(ans*mul[i%3] + in_dex[s[i]-'a'])%mod; return ans; }
现在处女座给你他想用来 hack 的第一个字符串 s1,和常数 p,q,r,t,请你帮他找出第二个字符串 s2,使得:get_hash(s1) = get_hash(s2)。
【输入描述】
输入数据共两行,第一行为四个整数 p,q,r,t,表示代码里的常数。
第二行为一个整数T,表示数据组数。
接下来一行,每行一个仅由小写字母构成的字符串 s1,表示处女座想用来hack的字符串。
【输出描述】
输出一行一个和 s1不同的仅由小写字母构成的字符串 s2,使得 get_hash(s1)=get_hash(s2) 且 |s2|≤20,000。
【样例】
示例1
输入
123 456 789 101
3
afyo
cycw
cogw
输出
cnztql
cnzak
cnzac
思路:
对长度 4 的小写字母的字符串共 475254 个(26*26*26*26),已经包括了 [0,9983] 的范围,因此对长度为 4 的字符串进行枚举即可,枚举时判断已构成的字符串的 hash 值是否与给的字符串的 hash 值相同,若相同则输出结果即可
【源代码】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define PI acos(-1.0)
#define E 1e-6
#define INF 0x3f3f3f3f
#define N 100001
#define LL long long
const int MOD=9983;
using namespace std;
int p,q,r,t;
int mul[3];
int in_dex[26];
char str[N],temp[N];
int get_hash(char *s){
int res=0;
int len=strlen(s);
for(int i=0;i<len;i++)
res=(res*mul[(i+1)%3]+in_dex[s[i]-'a'])%MOD;
return res;
}
int main()
{
scanf("%d%d%d%d",&p,&q,&r,&t);
mul[0]=p;
mul[1]=q;
mul[2]=r;
for(int i=0;i<26;i++)
in_dex[i]=i*t+t;
int T;
scanf("%d",&T);
while(T--){
scanf("%s",str);
int Hash=get_hash(str);
bool flag=true;
for(int i=0;i<26&&flag;i++){
temp[0]=(char)('a'+i);
for(int j=0;j<26&&flag;j++){
temp[1]=(char)('a'+j);
for(int k=0;k<26&&flag;k++){
temp[2]=(char)('a'+k);
for(int l=0;l<26&&flag;l++){
temp[3]=(char)('a'+l);
temp[4]='\0';
if(Hash==get_hash(temp)){
if(strcmp(temp,str)!=0){
printf("%s\n",temp);
flag=false;
}
}
}
}
}
}
}
return 0;
}