不知道这题该归类到什么东西里面。。。
可以发现,假设最终通过改变而相同的子串,假设他们一个结尾在i,一个结尾在j,设k=j-i,他们中的子串中任意两个下标%k相同的位置,他们的字符肯定也相同(结论。)
那么知道这一点后我们就可以开始乱搞了(迷)
我们先枚举周期k,然后扫一遍串。
每一次维护一个右指针r,表示最多能延伸到哪里,然后设一个need表示当前用了多少次机会,那么每次我们可以更新答案ans=max(ans,r-i-k)(k=j-i,r-i-k=r-j)
然后删除左指针,当然这都是在%k意义下进行的。
然后为了维护,我们要记录几个值:
cnt[i][j]表示在i%k的位置我出现了多少个字符为j
t[i][j]表示cnt[i]内有多少个值为j。
mx表示cnt[i]中的最大值。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define fd(i,a,b) for (int i=a;i>=b;i--)
using namespace std;
const int N=3e3+5;
int m,k,n,cnt[N][26];
int mx[N],need,ans,t[N][N];
char s[N];
inline void ins(int r,int x,int op)
{
if (op==1)
{
cnt[r][x]++;
need++;
int y=cnt[r][x];
t[r][y-1]--;t[r][y]++;
if (y>mx[r]) mx[r]=y,need--;
}
else
{
cnt[r][x]--;
need--;
int y=cnt[r][x];
t[r][y+1]--;
t[r][y]++;
if (!t[r][mx[r]]) mx[r]--,need++;
}
}
int main()
{
freopen("repeat.in","r",stdin);
freopen("repeat.out","w",stdout);
scanf("%d",&k);
scanf("%s",s+1);
n=strlen(s+1);
fo(l,1,n-1)
{
int r=0;
need=0;
fo(i,0,l-1)t[i][0]=26,mx[i]=0;
fo(i,1,n)
{
while (need<=k&&r<n) r++,ins(r%l,s[r]-'a',1);
ans=max(ans,r-i-l);
ins(i%l,s[i]-'a',-1);
}
fo(i,0,l-1)
fo(j,0,25)
t[i][cnt[i][j]]=0,cnt[i][j]=0;
}
printf("%d\n",ans);
return 0;
}