JZOJ5272. 神奇的重复序列 结论

来源:互联网 发布:图床源码 编辑:程序博客网 时间:2024/06/04 13:07

不知道这题该归类到什么东西里面。。。

可以发现,假设最终通过改变而相同的子串,假设他们一个结尾在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;}
原创粉丝点击