*点击

入门oj6489:文章评分(hash)

题目

Description

nodgd的文章由n个小写英文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度就是这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法,所以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,nodgd决定给自己的文章进行评分。nodgd 首先确定了一个整数m,然后统计出文章中有多少个不相同的长度为m的子串,这个数量就是文章的评分。

Input

第一行包含两个整数n,m,表示文章的长度和需要统计的子串长度。
1≤m≤n≤200000
第二行包含一个长度为n的只包含小写字母的字符串。

Output

一行一个整数,表示文章的评分。

Sample Input

5 3 
aaaab

Sample Output

2
【提示】
【样例解释1】
长度为3的子串有3个,分别是 aaa,aaa,aab,其中不同的只有2个。

HINT


 

思路:

一道很明显的$hash$题,我们可以用$map$来存每一个字串的$hash$值,再看有多少个不同的;

由于$oj$的数据强化了,所以要用双$hash$,但蒟蒻博主用双$hash$却和数据的答案有几个数的相差;

所以,博主用了三$hash$就过了;

 

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
const int mod=19260819,mod1=19260809,mod2=19260719;//防止数据过大的mod 
ll p[1000001],p1[1000001],p2[1000001],ha[1000001],ha1[1000001],ha2[1000001];
ll b=193,b1=137,b2=107;//每个hash值的进制   三hash 
ll n,m;
map<ll,bool> a,a1,a2;
char c[1000001];
int main()
{
    //不懂的去网上看hash基础,或私聊博主 
    p[0]=1;p1[0]=1;p2[0]=1;
    for(ll i=1;i<=1000001;i++)
        p[i]=p[i-1]*b%mod,
        p1[i]=p1[i-1]*b1%mod1,
        p2[i]=p2[i-1]*b2%mod2;//记录每一位上转进制时要乘的数 
    n=read();m=read();
    scanf("%s",(c+1));
    for(ll i=1;i<=n;i++)
        ha[i]=(ha[i-1]*b%mod+(c[i]-'A'+1))%mod,
        ha1[i]=(ha1[i-1]*b1%mod1+(c[i]-'A'+1))%mod1,
        ha2[i]=(ha2[i-1]*b2%mod2+(c[i]-'A'+1))%mod2;//把每一位上的hash值求出来 
    ll ans=0;
    for(ll i=1;i<=n-m+1;i++)//枚举每一个题目要求长度的字串 
    {
        ll t=((ha[i+m-1]-ha[i-1]*p[m]%mod)+mod)%mod;
        ll tt=((ha1[i+m-1]-ha1[i-1]*p1[m]%mod1)+mod1)%mod1;
        ll ttt=((ha2[i+m-1]-ha2[i-1]*p2[m]%mod2)+mod2)%mod2;//把字串的不同hash值求出 
        if(!a[t]||!a1[tt]||!a2[ttt])//如果没有出现过就ans++ 
            ans++;
        a[t]=1,a1[tt]=1,a2[ttt]=1;
    }
    printf("%lld",ans);
    return 0;
}

 

posted @ 2020-05-30 11:11  木偶人-怪咖  阅读(257)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录