今天主要还是关于hash和kmp的例题练习
目录
kmp例题
Radio Transmission 无线传输
题目描述
给你一个字符串 s_1s1,它是由某个字符串 s_2s2 不断自我连接形成的。但是字符串 s_2s2 是不确定的,现在只想知道它的最短长度是多少。
输入格式
第一行一个整数 LL,表示给出字符串的长度。
第二行给出字符串 s_1s1 的一个子串,全由小写字母组成。
输出格式
仅一行,表示 s_2s2 的最短长度。
说明/提示
样例输入输出 1 解释
对于样例,我们可以利用 \texttt{abc}abc 不断自我连接得到 \texttt{abcabcabc}abcabcabc,读入的 \texttt{cabcabca}cabcabca,是它的子串。
规模与约定
对于全部的测试点,保证 1 < L \le 10^61<L≤106。
思路
首先根据提示就可以知道给出的样例由一段子串不断自我连接出来的一个主串中的子串,直接上图:
由上图可知,我首先找出了给出字符串的最大前缀(红色线条)和对应的最大后缀(蓝色线条),然后会发现,将前缀部分和后缀部分重叠之后能够得到,一个由最小字符串组成的完整主串。
但是我这个举的是一个比较特殊的例子,如果是题目中给出的那样的例子,也是相同的道理
为什么会这样嘞,根据上面一个草图来看,可以知道,将前缀后缀分成了俩部分,一部分是重叠了的部分,一部分是未重叠的部分,这么分的原因是,将串延长一点可能会更加清楚
由上图可知,重复部分的字符是相对应的,所以最小字符串长度就是未重叠的长度。
代码
#include<stdio.h>
#include<string.h>
char str[1000010];
int next[1000010];
void get_next(int L)
{
int i=0,j=-1;
next[0] = -1;
while(i<L)
{
if(j==-1 || str[i]==str[j])
{
++i;
++j;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
int L;
scanf("%d",&L);
scanf("%s",str);
get_next(L);
printf("%d ",L-next[L]);
return 0;
}
hash例题
字符串哈希
题目描述
如题,给定 NN 个字符串(第 ii 个字符串长度为 M_iMi,字符串内包含数字、大小写字母,大小写敏感),请求出 NN 个字符串中共有多少个不同的字符串。
友情提醒:如果真的想好好练习哈希的话,请自觉。
输入格式
第一行包含一个整数 NN,为字符串的个数。
接下来 NN 行每行包含一个字符串,为所提供的字符串。
输出格式
输出包含一行,包含一个整数,为不同的字符串个数。
说明/提示
对于 30\%30% 的数据:N\leq 10N≤10,M_i≈6Mi≈6,Mmax\leq 15Mmax≤15。
对于 70\%70% 的数据:N\leq 1000N≤1000,M_i≈100Mi≈100,Mmax\leq 150Mmax≤150。
对于 100\%100% 的数据:N\leq 10000N≤10000,M_i≈1000Mi≈1000,Mmax\leq 1500Mmax≤1500。
样例说明:
样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。
Tip: 感兴趣的话,你们可以先看一看以下三题:
BZOJ3097:http://www.lydsy.com/JudgeOnline/problem.php?id=3097
BZOJ3098:http://www.lydsy.com/JudgeOnline/problem.php?id=3098
BZOJ3099:http://www.lydsy.com/JudgeOnline/problem.php?id=3099
如果你仔细研究过了(或者至少仔细看过AC人数的话),我想你一定会明白字符串哈希的正确姿势的^_^
思路
首先关于hash算法,我的理解是,就是将复杂简单化,通过取余的方式可以实现,也可以通过特殊的进制来达到目的,但是不管是什么情况,避免哈希冲突才是重点。
然后就是关于这个题目,可以先把字符串利用特殊的进制来达到区分不同的目的,然后将字符串转化为不同的数字之后,然后按序排好,然后就是找相同的数字,排除掉相同的字符串达到题目要求。
代码实现
#include<stdio.h>
#include<string.h>
#define num 10010
long long base(char str[])
{
long long sum=0;
for(int i=0; str[i]; i++)
sum=sum*11+str[i];
return sum;
}
int main()
{
long long base(char str[]);
long long n,hash[num];
scanf("%d",&n);
for(int i=0; i<n; i++)
{
char str[1510];
scanf("%s",str);
hash[i] = base(str);
}
for(int i=1; i<n; i++)
for(int k=0; k<n-1; k++)
{
long long x;
if(hash[k]>hash[k+1])
{
x=hash[k];
hash[k]=hash[k+1];
hash[k+1]=x;
}
}
int count = 0;
for(int i=0; i<n; i++)
{
if(hash[i]!=hash[i+1])
{
count++;
}
}
printf("%d",count);
return 0;
}