#10035. 「一本通 2.1 练习 1」Power Strings(字符串Hash)

10035. 「一本通 2.1 练习 1」Power Strings

在这里插入图片描述
AC代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstring>
#include<iostream>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000010;
int b=31;
ULL sum[N],power[N];
int len[N];
char s1[N];
void init()
{
	int i;power[0]=1;
	for(i=1;i<N;i++)
		power[i]=power[i-1]*b;
}
int Hash()
{
	int i,j,k,l,z;
	ULL s,ss;
	l=strlen(s1+1);z=1;
	for(i=1;i<=l;i++)
		if(l%i==0)
			len[z++]=i;//子字符串可能的长度 
	for(i=1;i<=l;i++)
		sum[i]=sum[i-1]*b+(ULL)(s1[i]-'A'+1);
	for(i=1;i<z;i++)
	{
		for(k=0;k<=l-len[i];k+=len[i])//子字符串首字符位置 -1  首位置是k+1 
		{
			s=sum[k+len[i]]-sum[k]*power[len[i]];
			if(ss==s&&k!=0)continue;//和上一个相同长度的子字符串的哈希值相同的直接跳过 
			for(j=0;j<=l-len[i];j+=len[i])//子字符串首字符位置 -1  首位置是k+1 
				if(s!=sum[j+len[i]]-sum[j]*power[len[i]])
					break;
			if(j==l)//子字符串重复且连接,因为是从一个长度的子字符串开始,所以只要找到就是最大的值
				return l/len[i];
			ss=s;//记录处理过的子字符串的哈希值,留到下次判断用 
		}
	}
	return 1;//因为都能从上面的出口出去这个return无所谓,但是交到oj上会有警告性错误 
}
int main()
{
	init();
	while(scanf("%s",s1+1),s1[1]!='.')
		printf("%d\n",Hash());
	return 0;
}

第一次思路:
最后一个样例超时

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000010;
int b=31;
ULL sum[N],power[N];
int len[N];
char s1[N];

void init()
{
	int i;power[0]=1;
	for(i=1;i<N;i++)
		power[i]=power[i-1]*b;
}
int Hash()
{
	int maxn,ans,i,j,k,l,kk,z;
	ULL s;
	l=strlen(s1+1);maxn=0;z=1;
	for(i=1;i<=l;i++)
		if(l%i==0)
			len[z++]=i;
	for(i=1;i<=l;i++)
		sum[i]=sum[i-1]*b+(ULL)(s1[i]-'A'+1);
	for(i=1;i<z;i++)
	{
		for(k=0;k<=l-len[i];k+=len[i])
		{
			s=sum[k+len[i]]-sum[k]*power[len[i]];
			for(j=0;j<=l-len[i];j+=len[i])
				if(s!=sum[j+len[i]]-sum[j]*power[len[i]])
					break;
			if(j==l)
				return l/len[i];
		}
	}
}
int main()
{
	init();
	while(scanf("%s",s1+1),s1[1]!='.')
		printf("%d\n",Hash());
	return 0;
}

第二次思路:
本想着标记过的跳过,优化一下
结果后四个样例超时

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<map>
#include<cstring>
#include<iostream>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000010;
map<string,int> mmm;
int b=31;
ULL sum[N],power[N];
int len[N];
char s1[N];
string str;
void init()
{
	int i;power[0]=1;
	for(i=1;i<N;i++)
		power[i]=power[i-1]*b;
}
int Hash()
{
	//****************************
	mmm.clear();//注意清空 
	//****************************
	int i,j,k,l,z;
	ULL s;
	l=strlen(s1+1);z=1;
	for(i=1;i<=l;i++)
		if(l%i==0)
			len[z++]=i;
	for(i=1;i<=l;i++)
		sum[i]=sum[i-1]*b+(ULL)(s1[i]-'A'+1);
	for(i=1;i<z;i++)
	{
		for(k=0;k<=l-len[i];k+=len[i])
		{
			s=sum[k+len[i]]-sum[k]*power[len[i]];
			//****************************
				if(mmm[str])continue;
				str.assign(s1+1,k,len[i]);
				mmm[str]=1;
				str.clear();//注意清空 
			//****************************
			for(j=0;j<=l-len[i];j+=len[i])
				if(s!=sum[j+len[i]]-sum[j]*power[len[i]])
					break;
			if(j==l)
				return l/len[i];
		}
	}
}
int main()
{
	init();
	while(scanf("%s",s1+1),s1[1]!='.')
		printf("%d\n",Hash());
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值