【JZOJ5272】【GDOI2018模拟】神奇的重复序列(DP,性质题)

来源:互联网 发布:数据库基本概念 编辑:程序博客网 时间:2024/05/19 02:16

Description

这里写图片描述

Solution

如果两个串重叠的话,那么很明显这个串会是一个周期串(画个图就知道了)。
枚举两个串的左端点的间距k,那么根据周期串的性质,在%k相同的地方都是相同的,那么我们枚举k,然后在枚举第一个串的左端点,然后用一个指针j向右扫过去。如果要把%k相同的修改为相同的话,那么就是保留其中出现次数最多的字符。那么我们对于%k的位置要存储每个字符出现多少次还有出现最多的是什么,和出现次数为p的个数,这个可以方便修改,当i向右移的时候,假如最大值的个数变为了0,那么最大值也最多向左移一位。每次j都一道不能再移为止。
最后j-i+1-k就是答案

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=3007;int i,j,k,l,t,n,m,ans,p,kk;char s[maxn];int a[maxn],d[220][maxn],b[maxn],c[maxn],o,g[maxn][maxn];int main(){    freopen("repeat.in","r",stdin);    freopen("repeat.out","w",stdout);    scanf("%d",&kk);    scanf("%s",s+1);n=strlen(s+1);fo(i,1,n)a[i]=s[i]-'a';    fo(k,1,n){        j=k-1;o=0;fo(i,1,j)g[i][0]++;        fo(i,1,j){            t=++d[a[i]][i];g[i][t]++;g[i][t-1]--;            if(t>c[i])c[i]=t;else o++;        }        fo(i,1,n-k){            while(j+1<=n){                if(d[a[j+1]][(j+1)%k]+1<=c[(j+1)%k]&&o+1>kk)break;                j++;t=++d[a[j]][j%k];g[j%k][t]++;g[j%k][t-1]--;                if(t>c[j%k])c[j%k]=t;                else o++;            }            t=--d[a[i]][i%k];g[i%k][t]++,g[i%k][t+1]--;            if(!g[i%k][c[i%k]])c[i%k]--;else o--;            ans=max(ans,j-i+1-k);        }        fo(i,1,j){            g[i%k][d[a[i]][i%k]]=0;            d[a[i]][i%k]=0;            c[i%k]=0;        }    //  memset(d,0,sizeof(d));memset(g,0,sizeof(g));memset(c,0,sizeof(c));    }    printf("%d\n",ans);}
阅读全文
1 0
原创粉丝点击