1691:文章评分
时间限制: 1000 ms 内存限制: 262144 KB
提交数: 1598 通过数: 287
【题目描述】
nodgd的文章由nn个小写英文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度就是这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法,所以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,nodgd决定给自己的文章进行评分。nodgd 首先确定了一个整数mm,然后统计出文章中有多少个不相同的长度为mm的子串,这个数量就是文章的评分。
【输入】
第一行包含两个整数n,mn,m,表示文章的长度和需要统计的子串长度。
第二行包含一个长度为nn的只包含小写字母的字符串。
【输出】
一行一个整数,表示文章的评分。
【输入样例】
5 3
aaaab
【输出样例】
2
【提示】
【样例解释1】
长度为33的子串有33个,分别是 aaa,aaa,aabaaa,aaa,aab,其中不同的只有22个。
【输入样例2】
9 3 abcabacba 【输出样例2】
7
【样例解释2】
共有77个长度为33的子串,每个长度为33的子串都不同。
【数据规模】
对于 30%的数据,1≤m≤n≤2001≤m≤n≤200。
对于 50%的数据,1≤m≤n≤20001≤m≤n≤2000。
对于另外 20%的数据,1≤m≤50≤n≤2000001≤m≤50≤n≤200000。
对于 100%的数据,1≤m≤n≤2000001≤m≤n≤200000。
奉上代码:
#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;
ll p[1000001],p1[1000001],p2[1000001],ha[1000001],ha1[1000001],ha2[1000001];
ll b=193,b1=137,b2=107;
ll n,m;
map<ll,bool> a,a1,a2;
char c[1000001];
int main(){
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;
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;
if(!a[t]||!a1[tt]||!a2[ttt])
ans++;
a[t]=1,a1[tt]=1,a2[ttt]=1;
}
printf("%lld",ans);
return 0;
}