题目描述
福尔摩斯从 X 星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为 88 的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。
请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。
输入格式
输入第一行:一个字符串 ss,全部由小写字母组成,长度小于 1024 \times 10241024×1024。
紧接着一行是一个整数 n,n, 表示以下有 nn 行密码,1 \le n \le 10001≤n≤1000。
紧接着是 nn 行字符串,都是小写字母组成,长度都为 88。
输出格式
一个整数,表示每行密码的所有排列在 ss 中匹配次数的总和。
输入输出样例
输入 #1复制
aaaabbbbaabbcccc 2 aaaabbbb abcabccc输出 #1复制
4说明/提示
第一个密码匹配了 33 次,第二个密码匹配了 11 次,一共 44 次。
时限 3 秒, 512M。蓝桥杯 2015 年第六届国赛
1.这个题目用的是hash算法。
2.题目的意思是吧密码打乱,也就是说重新排列,得到新的一串字符串,然后在母串当中寻找该子串。在母串找的时候必须是连续的8个。
3.那我们如何使用hash函数? 我们知道hash函数能够使相同的字符串得出的值相等,那么,如果,字符串里面的字符相对应是相等的,我们要是的通过hash函数使得他们相等:
让这俩个字符串相等,我们可以利用字符对应的ASCII码来做一个hash值,这样的话,如果相对于字符串的全排列,那样子hash函数 得出的值会是一样的。
如果设计我刚开始设计的是让ASCII码值 乘以 字符在字母表的顺序,但是只AC了四个测试点,我们可以改为平方法。乘以俩个ASCII码值。
4.然后就是一些细节:我们处理母串时,每8个生成一个hash值,然后排序即可。最后拿密码串去查找对应的hash值。排序建议使用快排,查找建议使用二分。
C代码如下:
#include<stdio.h>
#include<string.h>
#define N 1050000
char s[N];
int hash[N];
int n,c[27],m;
int quicksort(int left,int right)
{
if(left>=right) return 0;
int i=left,j=right,t,temp=hash[left];
while(i<j)
{
while(i<j&&hash[j]>=temp) j--;
while(i<j&&hash[i]<=temp) i++;
if(i<j)
{
t=hash[i];hash[i]=hash[j];hash[j]=t;
}
}
hash[left]=hash[i];
hash[i]=temp;
quicksort(left,i-1);
quicksort(i+1,right);
}
int chazhao(int left,int right,int x)
{
if(left>right) return -1;
if(hash[left]==x) return left;
if(hash[right]==x) return right;
int mid=(left+right)/2;
if(hash[mid]==x) return mid;
else if(hash[mid]>x) chazhao(left,mid-1,x);
else chazhao(mid+1,right,x);
}
int csh()
{
int i,j;
for(i=0;i<8;i++)
{
hash[0]+=(s[i]-'a'+1)*s[i]*s[i];
}
j=1;
for(i=8;s[i];i++)
{
hash[j]=hash[j-1]-(s[i-8]*s[i-8]*(s[i-8]-'a'+1))+(s[i]-'a'+1)*s[i]*s[i];
j++;
}
n=j;
}
int hsh(char t[])
{
int i,k=0,j,sum=0;
for(i=0;i<8;i++)
{
k+=(t[i]-'a'+1)*t[i]*t[i];
}
j=chazhao(0,n-1,k);
// printf("j %d k%d",j,k);
if(j==-1) return 0;
for(i=j-1;i>=0&&hash[i]==k;i--)sum++;
for(i=j+1;i<n&&hash[i]==k;i++) sum++;
//printf("%d ",sum);
return sum+1;
}
int main()
{
int i;
char t[10];
long long sum=0;
scanf("%s",s);
csh();
quicksort(0,n-1);
// for(i=0;i<n;i++) printf("%d ",hash[i]);
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%s",t);
sum+=hsh(t);
}
printf("%lld",sum);
}
C++代码为:
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
const int N=1050000;
char s[N];
int hashz[N];
int n,m;
int cmp(int a,int b)
{
return a>b;
}
int csh()
{
int i,j;
for(i=0;i<8;i++)
{
hashz[0]+=(s[i]-'a'+1)*s[i]*s[i];
}
j=1;
for(i=8;s[i];i++)
{
hashz[j]=hashz[j-1]-(s[i-8]*s[i-8]*(s[i-8]-'a'+1))+(s[i]-'a'+1)*s[i]*s[i];
j++;
}
n=j;
}
int hsh(char t[])
{
int i,k=0,j,sum=0;
for(i=0;i<8;i++)
{
k+=(t[i]-'a'+1)*t[i]*t[i];
}
j=lower_bound(hashz,hashz+n-1,k)-hashz;
for(i=j;i<n&&hashz[i]==k;i++) sum++;
return sum;
}
int main()
{
int i;
char t[10];
long long sum=0;
cin >> s;
csh();
sort(hashz,hashz+n-1,cmp);
cin >> m;
for(i=0;i<m;i++)
{
cin >> t;
sum+=hsh(t);
}
cout << sum << endl;
return 0;
}