求一个字符串中正好出现了K次的子串,可以用后缀自动机来做
附上后缀自动机的应用:https://blog.csdn.net/clover_hxy/article/details/68059043
以及代码出处:https://www.cnblogs.com/forever97/p/hdu6194.html
本来套了个kuangbin模板,提交结果内存爆了,因为用的都是指针(64位系统指针占用空间比int大)
就直接套用别人写的代码了
写这题刚学习了后缀自动机的结构和构造,勉强理解了大概
后缀自动机的用处很多,以后要多做一些应用题,加深理解
#include <cstdio>
#include<iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=200010;
char s[N];
struct SAM{
int p,q,np,nq,cnt,lst,a[N][26],l[N],f[N],tot;
int Tr(char c){return c-'a';}
int val(int c){return l[c]-l[f[c]];}
SAM(){cnt=0;lst=++cnt;}
void Initialize(){
memset(l,0,sizeof(int)*(cnt+1));
memset(f,0,sizeof(int)*(cnt+1));
for(int i=0;i<=cnt;i++)for(int j=0;j<26;j++)a[i][j]=0;
cnt=0;lst=++cnt;
}
void extend(int c){
p=lst;np=lst=++cnt;l[np]=l[p]+1;
while(!a[p][c]&&p)a[p][c]=np,p=f[p];
if(!p){f[np]=1;}
else{
q=a[p][c];
if(l[p]+1==l[q])f[np]=q;
else{
nq=++cnt;l[nq]=l[p]+1;
memcpy(a[nq],a[q],sizeof(a[q]));
f[nq]=f[q]; f[np]=f[q]=nq;
while(a[p][c]==q)a[p][c]=nq,p=f[p];
}
}
}
int b[N],x[N],r[N];
void build(int len){
Initialize();
for(int i=1;i<=len;i++)extend(Tr(s[i]));
}
void solve(){
int ans=0,k;
scanf("%d",&k);
scanf("%s",s+1); //从下标1开始
int len=strlen(s+1);
build(len);
memset(r,0,sizeof(int)*(cnt+1));
memset(b,0,sizeof(int)*(cnt+1));
for(int i=1;i<=cnt;i++)b[l[i]]++;
for(int i=1;i<=len;i++)b[i]+=b[i-1];
for(int i=1;i<=cnt;i++)x[b[l[i]]--]=i;
for(int i=p=1;i<=len;i++){p=a[p][Tr(s[i])];r[p]++;}
for(int i=cnt;i;i--)r[f[x[i]]]+=r[x[i]];
for(int i=1;i<=cnt;i++)if(r[x[i]]==k)ans+=val(x[i]);
printf("%d\n",ans);
}
}sam;
int T;
int main(){
scanf("%d",&T);
while(T--){
sam.solve();
}return 0;
}