4641因为是多组数据所以为了方便把板子改成了用数组的二而不是指针的写法。
计算出现k次以上的字符串一共有几个。
对于已经建立好的SAM,每加入一个字符,多出来了一次的字符串就是所有的以这个字符为结尾的后缀字符串。
所以只需要统计加入这个字符之后又多了几个就可以了,用后缀数组就可以实现。
记录一下每个状态的right集合的大小(size的求法可以想象成一个树形dp)
然后如果某种状态的right集合的大小达到了K,那么就将答案加上val[p]-val[fa[p]]
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#define N 500005
#define INF 0x3f3f3f3f
using namespace std;
char s[50005];
char s1[10];
int n,m,k,tot=0;
long long ans=0;
struct state{
state *par, *go[26];
int val,size; //val==maxlen fst==very left
state(int _val) :
par(0), val(0), size(0){
memset(go,0,sizeof(go));
}
};
struct suffixautomaton{
int fa[N],go[N][26];
int val[N], size[N];
int root,last;
int id;
void extend(int w){
int p=last;
int np=++id;
val[np]=val[p]+1;
while (p!=-1&&go[p][w]==0){
go[p][w]=np;
p=fa[p];
}
if (p==-1) fa[np]=root;
else{
int q=go[p][w];
if (val[p]+1==val[q]){
fa[np]=q;
}
else{
int nq=++id;
val[nq]=val[p]+1;
memcpy(go[nq],go[q],sizeof(go[q]));
size[nq]=size[q];
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
while (p!=-1&&go[p][w]==q) {
go[p][w]=nq;
p=fa[p];
}
}
}
last=np;
while (np&&size[np]<k){
size[np]++;
if (size[np]>=k) ans+=(val[np]-val[fa[np]]);
np=fa[np];
}
}
void init(char *s){
memset(go,0,sizeof(go));
memset(val,0,sizeof(val));
memset(size,0,sizeof(size));
memset(fa,0,sizeof(fa));
root=last=id=0;
fa[root]=-1;
int len=strlen(s+1);
for (int i=1;i<=len;i++){
extend(s[i]-'a');
}
}
}A;
int main(){
while (scanf("%d%d%d",&n,&m,&k)!=EOF){
ans=0;
scanf("%s",s+1);
A.init(s);
int typ;
while (m--){
scanf("%d",&typ);
if (typ==1){
scanf("%s",s1);
A.extend(s1[0]-'a');
}
else{
printf("%lld\n",ans);
}
}
}
return 0;
}
这个题目刚开始使用memset超时……佛了
后来又因为调试代码没有删除WA了几次……
题目是后缀数组的板子题目?
求某个子串中相互不相同的子串的个数,由于字符串的大小只有2000,所以就可以直接预处理好所有的情况然后回答。
预处理的方法就是裸的SAM加上一句话……
加上这个字符之后如果出现了一个新的字符串,这个字符串一定是长度在(val[fa[p]], val[p]]之间的。
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#define N 100005
#define LEN 2005
using namespace std;
char s[LEN];
int n,m,k,tot=0;
int ans[LEN][LEN];
struct suffixautomaton{
int fa[N],go[N][26];
int val[N];
int root,last;
int id, sum;
int newnode(int v){
id++;
for (int i=0;i<26;i++) go[id][i]=0;
val[id]=v;
return id;
}
void extend(int w){
int p=last;
int np=newnode(val[p]+1);
while (p!=-1&&go[p][w]==0){
go[p][w]=np;
p=fa[p];
}
if (p==-1) fa[np]=root;
else{
int q=go[p][w];
if (val[p]+1==val[q]){
fa[np]=q;
}
else{
int nq=newnode(val[p]+1);
memcpy(go[nq],go[q],sizeof(go[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
while (p!=-1&&go[p][w]==q) {
go[p][w]=nq;
p=fa[p];
}
}
}
last=np;
sum+=(val[np]-val[fa[np]]);
return;
}
void init(char *s, int st, int len){
id=-1;
root=last=newnode(0);
fa[root]=-1;
sum=0;
for (int i=st;i<=len;i++){
extend(s[i]-'a');
ans[st][i]=sum;
}
}
}A;
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%s",s+1);
int len=strlen(s+1);
for (int i=1;i<=len;i++){
A.init(s,i,len);
}/*
for (int i=1;i<=len;i++){
for (int j=i;j<=len;j++){
cout<<ans[i][j]<<" ";
}
cout<<endl;
}*/
int m,l,r;
scanf("%d",&m);
while (m--){
scanf("%d%d",&l,&r);
printf("%d\n",ans[l][r]);
}
}
}