正题
题目链接:https://www.luogu.com.cn/problem/P5341
题目大意
给出一个字符串,求出现次数恰好为kkk的子串中,出现最多的长度。
解题思路
先根据TTT构建一个SAMSAMSAM,对于一个endposendposendpos类中,所有出现串的长度一定是一个连续的区间。
所以我们直接计算出每个endposendposendpos类的大小,如果是kkk,就差分让[lenfx+1,lenx][len_{f_x}+1,len_{x}][lenfx+1,lenx]加111。
时间复杂度O(n)O(n)O(n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2e5+10;
ll T,n,k,a[N],c[N],rk[N],num[N];
ll cnt,last,fa[N],ch[N][26],len[N];
char s[N];
void insert(ll c){ll p=last,np=last=++cnt;len[np]=len[p]+1;num[cnt]++;for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;if(!p)fa[np]=1; else{ll q=ch[p][c];if(len[p]+1==len[q])fa[np]=q;else{ll nq=++cnt;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[nq]));fa[nq]=fa[q];fa[q]=fa[np]=nq;for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;}}return;
}
int main()
{scanf("%lld",&T);while(T--){last=cnt=1;memset(ch[1],0,sizeof(ch[1]));scanf("%s",s+1);n=strlen(s+1);for(ll i=1;i<=n;i++)insert(s[i]-'a'),a[i]=c[i]=0;scanf("%lld",&k);bool flag=0;for(ll i=1;i<=cnt;i++)c[len[i]]++;for(ll i=1;i<=n;i++)c[i]+=c[i-1];for(ll i=1;i<=cnt;i++)rk[c[len[i]]--]=i;for(ll i=cnt;i>=1;i--)num[fa[rk[i]]]+=num[rk[i]];for(ll i=2;i<=cnt;i++)if(num[i]==k)a[len[i]]++,a[len[fa[i]]]--,flag=1;for(ll i=n;i>=0;i--)a[i]+=a[i+1];ll mark=0;a[0]=0;for(ll i=1;i<=n;i++)if(a[i]>=a[mark])mark=i;if(!flag)printf("-1\n");else printf("%lld\n",mark);for(ll i=0;i<=cnt;i++)num[i]=fa[i]=len[i]=0,memset(ch[i],0,sizeof(ch[i]));}
}