POJ 1743 不可重叠的最长重复子串

原问题,其实是找最长的相似子串,所谓相似就是一个子串每个值加上一个偏移值可以得到另一个子串。

我们先求原数组的差值数组,对新数组求后缀数组,二分答案,判定是否有某个Height数组中的sa最小值与最大值之差大于当前枚举的子串长度。

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <cassert>
#include <sstream>
using namespace std;

const int N=2e6+10010;

int sa[N];
int t1[N],t2[N],c[N];
int rk[N],height[N];

inline int cmp(int *r,int a,int b,int l){
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
int s[N];
void calcSA (int *s,int n,int m) {
    int i,j,p,*x=t1,*y=t2;
    for(i=0;i<m;i++)c[i]=0;
    for(i=0;i<n;i++)c[x[i]=s[i]]++;
    for(i=1;i<m;i++)c[i]+=c[i-1];
    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(j=1;j<=n;j<<=1){
        p=0;
        for(i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[y[i]]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}

void calcHeight(int *s,int n) {
    int i,j,k=0;
    for(i=0;i<=n;i++)rk[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k)k--; // h[i]>=h[i-1]-1
        j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位
        while(s[i+k]==s[j+k])k++; // 暴力计算lcp
        height[rk[i]]=k;
    }
}

bool ok(int n,int m) {
    int mi=sa[1],mx=sa[1];
    for (int i=2;i<=n;i++) {
        if (height[i]<m) {
            mi=sa[i];
            mx=sa[i];
            continue;
        }
        mi=min(mi,sa[i]);
        mx=max(mx,sa[i]);
        if (mx-mi>m) return true;
    }
    return false;
}

int a[N];
int main () {
    int n;
    while (scanf("%d",&n)!=EOF,n) {
        for (int i=0;i<n;i++)
            scanf("%d",a+i);
        --n;
        for (int i=0;i<n;i++) {
            s[i]=a[i+1]-a[i]+100; // 保证正数
        }
        s[n]=0;
        calcSA(s,n+1,200);
        calcHeight(s,n);
        int l=4,r=n/2,ret=-1;
        while (l<=r) {
            int m=(l+r)>>1;
            if (ok(n,m)) {
                ret=m;
                l=m+1;
            }
            else
                r=m-1;
        }
        printf("%d\n",ret+1);
    }
    return 0;
}
时间: 2024-08-26 07:51:00

POJ 1743 不可重叠的最长重复子串的相关文章

字符串----不可重叠的最长重复子串

题目:给定一个字符串,求最长重复子串,这两个子串不能重叠.例如,str = "acdcdcdcd",则不可重叠的最长子串为"cdcd". 思路:二分枚举+height数组分组.这道题的思想很巧妙,后面要仔细推敲.先二分答案,把题目变成判定性问题:判断是否存在两个长度为k的子串是相同的,且不重叠.解决这个问题的关键还是利用height数组.把排序后的后缀分成若干组,其中每组的后缀之间的height值都不小于k.例如,字符串为“aabaaaab”,当k=2时,后缀分成了

poj 1743 二分答案+后缀数组 求不重叠的最长重复子串

题意:给出一串序列,求最长的theme长度 (theme:完全重叠的子序列,如1 2 3和1 2 3  or  子序列中每个元素对应的差相等,如1 2 3和7 8 9) 要是没有差相等这个条件那就好办多了,直接裸题. 一开始想了个2B方法,后来发现真心2B啊蛤蛤蛤 1 for i=1 to 88 do 2 { 3 for j=1 to length 4 { 5 r2[j]=r[j]+i; 6 if (r2[j]>88) r2[i]-=88; 7 } 8 把新序列r2连接到原序列r的后面 9 pr

后缀数组(至少重复k次的可重叠的最长重复子串)—— POJ 3882

对应POJ 题目:点击打开链接 Stammering Aliens Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description Dr. Ellie Arroway has established contact with an extraterrestrial civilization. However, all efforts to decode their m

【POJ1743】不可重叠最长重复子串

题意:求一个字符串里两个不重叠的最长重复子串 代码如下: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 int sa[20010],rank[20010],y[20010],Rsort[20010]; 8 int wr[20010],a[20010],height[20010],n; 9 10

可重叠的k次最长重复子串

题目链接:https://cn.vjudge.net/contest/318888#problem/B 题意: 约翰注意到奶牛产奶的之类是不断变化的,虽然他不能预测从当天到下一天的变化情况但是他知道变化是有规律的,牛奶的质量由一个整数表示,范围从0到1000000,现在给定一个长度为n的序列,要求找到一个最大子序列,该子序列重复出现至少k次,各个出现部分可有重叠,求最长的长度.简单来说就是可重叠的k 次最长重复子串. 简单来说就是求可重叠的k次最长重复子串 思路: 这题首先先看数据的范围,发现相

POJ - 3261 Milk Patterns (后缀数组求可重叠的 k 次最长重复子串)

Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can't predict the quality of milk from one day to the next, there are some regular pattern

POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)

Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14094   Accepted: 6244 Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation,

POJ 3261 可重叠的 k 次最长重复子串【后缀数组】

这也是一道例题 给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠.算法分析:这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组.不同的是,这里要判断的是有没有一个组的后缀个数不小于 k.如果有,那么存在k 个相同的子串满足条件,否则不存在.这个做法的时间复杂度为 O(nlogn). Source Code: //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include

poj 3261 求可重叠的k次最长重复子串

题意:求可重叠的k次最长重复子串的长度 链接:点我 和poj1743差不多 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000