每日总结 1.13

1.今天刷了一题kmp还有一题hash

                          【模板】字符串哈希

题目描述

如题,给定 NN 个字符串(第 ii 个字符串长度为 M_iMi​,字符串内包含数字、大小写字母,大小写敏感),请求出 NN 个字符串中共有多少个不同的字符串。

友情提醒:如果真的想好好练习哈希的话,请自觉。

输入格式

第一行包含一个整数 NN,为字符串的个数。

接下来 NN 行每行包含一个字符串,为所提供的字符串。

输出格式

输出包含一行,包含一个整数,为不同的字符串个数。

输入输出样例

输入 #1复制

5
abc
aaaa
abc
abcc
12345

输出 #1复制

4

说明/提示

对于 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人数的话),我想你一定会明白字符串哈希的正确姿势的^_^

#include<stdio.h>
#include<string.h>
int len[1501];
int k[10000][10000];//记录字符存入散列表后的位置 
int hash[10000],hashh=0;
char str[10000][10000];
int main()
{
	long long int n;
	int cnt;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",str[i]);
		int L;
		L=strlen(str[i]);
		len[L]++;
		k[L][len[L]]=i;
		for(int j=1;j<=L;j++)
		{
			int A;
			A=str[i][j]-'0';
			hashh=hashh*10000+A;
		}
		hash[i]=hashh;
		for(int j=1;j<len[L];j++)
		{
			if(hash[k[L][j]]==hashh)
			{
				cnt++;
				break;
			}
		}
		hashh=0;
	}
	printf("%lld",n-cnt);
	getchar();
	getchar();
	return 0;
}

这个思路是后来才想出来的下面是一开始的思路只过了两个

#include<stdio.h>
#include<string.h>
#define N 10010
int a[N];
char str[N];
int n,count=1,t=121;
unsigned long long int mod=202240170506;
int hash(char str[])
{
	unsigned long long int k=0;
	for(int i=0;i<strlen(str);i++)
	{
		k=(k*t+(unsigned long long)str[i])%mod;
	}
	return k;
}
int main()
{
	int temp;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%s",str);
		a[i]=hash(str);
	}
	for(int i=0;i<n-1;i++)
	{
		for(int j=0;j<n-i;j++)
		{
			if(a[i]>=a[j])
			{
				temp=a[i];
				a[i]=a[j];
				a[j]=temp;
			}
		}
	}
	for(int i=0;i<n-1;i++)
	{
		if(a[i]!=a[i+1])
		{
			count++;
		}
	}
	printf("%d",count);
	getchar();
	getchar();
	return 0;
}

 简单说一下这个思路,这个是典型的hash求余数的策略,其中用了一个冒泡排序对给各个数即hash数进行排序,验证是否求的hash值相邻的相等,就一个一个叠加,最后得出答案,可是仍然有bug,实在做不出来就换了一个思路,后来的思路就是开几个数组以单词长度作为匹配的标准在相同的长度单词中间进行判断可以减低匹配复杂度,两个思路用的都是hash里面比较基础的一个是取余法还有一个是ascll码值,用一个数组存储,进行做个判断,以ascll码值来作为最后的判断依据,双重判断条件降低重复可能性。

               [BOI2009]Radio Transmission 无线传输 

题目描述

给你一个字符串 s_1s1​,它是由某个字符串 s_2s2​ 不断自我连接形成的。但是字符串 s_2s2​ 是不确定的,现在只想知道它的最短长度是多少。

输入格式

第一行一个整数 LL,表示给出字符串的长度。

第二行给出字符串 s_1s1​ 的一个子串,全由小写字母组成。

输出格式

仅一行,表示 s_2s2​ 的最短长度。

输入输出样例

输入 #1复制

8
cabcabca

输出 #1复制

3

说明/提示

样例输入输出 1 解释

对于样例,我们可以利用 \texttt{abc}abc 不断自我连接得到 \texttt{abcabcabc}abcabcabc,读入的 \texttt{cabcabca}cabcabca,是它的子串。

规模与约定

对于全部的测试点,保证 1 < L \le 10^61<L≤106。

#include<stdio.h>
#define N 1000010
int n,next[N];
char s[N];
int getnext()
{
	int i,j=0;
	for(i=1;i<n;)
	{
		while(i<n&&s[i]==s[j])
		{
			j++;
			next[i]=j;
			i++;
		}
		if(i>=n)
		{
			break;
		}
		j=next[j-1];
		while(i<n&&s[i]!=s[j]&&j==0)
		{
			i++;
		}
	}
}
int main()
{
	scanf("%d",&n);
	scanf("%s",s);
	getnext();
	printf("%d",n-next[n-1]);
	getchar();
	getchar();
	return 0;
}

这一题比较灵活了一点点,主要是考察一个kmp算法你对最长前后缀的理解程度,这边就是求出来重复的就是把最长前后缀减去就能得到最后的值。仅仅在kmp模板上面修改了一点点内容,主要的核心部分还是求next数组

今天还看了hash,kmp的视频,ac了两题所实话感觉kmp算法,和hash看了好多视频,对实现思路是没什么问题,但是真要自己打的话,比较之前的bfs,dfs没有那么简单对于代码这块还是得加强思路这方面的 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值