【JZOJ 5272】神奇的重复序列

来源:互联网 发布:人物漫画制作软件 编辑:程序博客网 时间:2024/05/16 17:22

Description

这里写图片描述

Solution

枚举两字符串的开头,暴力往后扫大家应该会做吧,
设两字符串开头为x,y(x<y),设k=yx
我们发现,如果对于多个位置,如果它在所在串的相对位置%k是相同的,那么这几个位都必须相同,
比如:两串的开头为1、3,k=2,那么,1、3、5、7等都必须相等,
换句话说,就是在两串相交时,会有一定的周期性,
(大家写两个数据看看就可以知道了)

发现开头没有必要一个个枚举,直接设前面开头为位置1,然后贪心找到合法的最右边,再弹掉开头即可,

复杂度:O(n226)

Code

#include <cstdio>#include <cstdlib>#define fo(i,a,b) for(int i=a;i<=b;i++)#define min(q,w) ((q)>(w)?(w):(q))#define max(q,w) ((q)<(w)?(w):(q))using namespace std;const int N=3500;int m,n,ans;int a[N];int b[N][28],bs[N];int z[N],TI;void UPD(int q){    int e=0;    fo(i,1,26)e=max(e,b[q][i]);    bs[q]=b[q][0]-e;}int main(){    int q,w,e;    scanf("%d",&m);    char ch=' ';    for(;ch<'a'||ch>'z';ch=getchar());    for(;ch<='z'&&ch>='a';ch=getchar())a[++n]=ch-96;    ans=min(m,n);    fo(I,1,n)    {        fo(i,0,I)        {            bs[i]=0;            fo(j,0,26)b[i][j]=0;        }        q=0;TI++;        int S=1,T;        for(T=1;I+T<=n;T++)        {            w=T%I;            if(z[T]<TI)b[w][a[T]]++,b[w][0]++;            b[w][a[T+I]]++,b[w][0]++;            z[T]=z[T+I]=TI;            q-=bs[w];            UPD(w);            q+=bs[w];            for(;q>m;S++)            {                int t=S%I;                b[t][a[S]]--;                b[t][0]--;                q-=bs[t];                UPD(t);                q+=bs[t];                z[S]=0;            }            ans=max(ans,T-S+1);        }    }    printf("%d\n",ans);    return 0;}
原创粉丝点击