ssl1211.好文章 字符串

题目

nodgd写了一篇文章,自认为这是一篇好文章。nodgd的文章由n个小写英文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度就是这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法,所以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,nodgd决定给自己的文章进行评分。nodgd首先确定了一个整数m,然后统计出文章中有多少个不相同的长度为m的子串,这个数量就是文章的评分。
然而,nodgd懒得老老实实计算这个评分了,就把任务丢给了你。
对于30%的数据,1≤m≤n≤200; 对于50%的数据,1≤m≤n≤2000; 对于另外20%的数据,1≤m≤50≤n≤200000; 对于100%的数据,1≤m≤n≤200000。

题解

把字符串每一位用一个数m(最好是质数)乘起来,然后取出一段时就用末位的值减去首位前一位*m的长度次方,得到的是就是它的hash值
要采用双哈希,用两个大的质数,比如1e9+7,998224353,或者一些奇怪而没有规律的数,防止被卡
然后就可以了

代码

#include <cstdio>

using namespace std;

const int lwq=100000007,hxh=99824353;
int n,m,ans;
char a[200005];
bool a1[lwq+6],a2[hxh+6];
long long h1[200005],h2[200005];
long long p1,p2;

int main(){
	
	scanf("%d%d",&n,&m);
	scanf("%s",a+1);
	for (int i=1;i<=n;i++){
		h1[i]=(h1[i-1]*181+a[i]-'a')%lwq;
		h2[i]=(h2[i-1]*107+a[i]-'a')%hxh;
	}
	p1=p2=1;
	for (int i=1;i<=m;i++)
		p1=(p1*181)%lwq,p2=(p2*107)%hxh;
	for (int i=m;i<=n;i++){
		int d1=0,d2=0;
		d1=((long long)h1[i]-h1[i-m]*p1)%lwq,
		d2=((long long)h2[i]-h2[i-m]*p2)%hxh;
		if (d1<0) d1+=lwq;
		if (d2<0) d2+=hxh;
		if (a1[d1]&&a2[d2]) continue;
		a1[d1]=1;a2[d2]=1;ans++;
	}
	printf("%d",ans); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值