JZOJ5272. 神奇的重复序列 结论

3 篇文章 0 订阅

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

可以发现,假设最终通过改变而相同的子串,假设他们一个结尾在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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值