题意 : 给出一个长度为 N 的序列,再给出一个 K 要求求出出现了至少 K 次的最长可重叠子串的长度

分析 : 后缀数组套路题,思路是二分长度再对于每一个长度进行判断,判断过程就是对于 Height 数组进行限定长度的分组策略,如果有哪一组的个数 ≥  k 则说明可行!

分组要考虑到一个事实,对于每一个后缀,与其相匹配能够产生最长的LCP长度的串肯定是在后缀数组中排名与其相邻。

一开始对分组的理解有误,所以想了一个错误做法 ==>

遍历一下 Height 将值 ≥ (当前二分长度) 的做一次贡献即 cnt++ ,若最后 cnt ≥ K 说明可行。当然这个肯定是炸了.......

下面说说我对于 Height 分组的理解吧,就看上面的图,如果当前 K == 2,那么第一组的含义是什么?换句话说就是为什么那么些个后缀要属于一组?可以看出第一组里面的 Height 值都不会小于 K ,实际的意义呢应当是第一组里面的有一个长度为 2 (不小于K)的共同前缀,即 “aa” ,那么是不是 “aa” 这个子串可重叠地出现了 cnt 次(cnt为第一组的后缀个数),可能你已经有点体会到分组的意义了!那么有没有可能有些前缀是 “aa” 但是没有被分进第一组呢?看见上面红字描述的事实么?根据上面的那个事实,而且 Height 的下标是根据排名有序的这个特点(有序的意思就是从小到大遍历 Height 实际传进去的下标就是排名!即 Height[i],i是表示第 i 名的后缀),我们就知道这样的事情不会发生,且分出来的组肯定的“连续的块”,即不会有这一组的元素在其他地方的可能性!

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
;

int sa[maxn], s[maxn], wa[maxn], Ws[maxn], wv[maxn], wb[maxn];
int Rank[maxn], height[maxn];

bool cmp(int r[], int a, int b, int l){ return r[a] == r[b] && r[a+l] == r[b+l]; }
void da(int r[], int sa[], int n, int m)
{
    int i, j, p, *x = wa, *y = wb;
    ; i < m; ++i) Ws[i] = ;
    ; i < n; ++i) Ws[x[i]=r[i]]++;
    ; i < m; ++i) Ws[i] += Ws[i-];
    ; i >= ; --i) sa[--Ws[x[i]]] = i;
    , p = ; p < n; j *= , m = p)
    {
        , i = n - j; i < n; ++i) y[p++] = i;
        ; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
        ; i < n; ++i) wv[i] = x[y[i]];
        ; i < m; ++i) Ws[i] = ;
        ; i < n; ++i) Ws[wv[i]]++;
        ; i < m; ++i) Ws[i] += Ws[i-];
        ; i >= ; --i) sa[--Ws[wv[i]]] = y[i];
        , x[sa[]] = , i = ; i < n; ++i)
            x[sa[i]] = cmp(y, sa[i-], sa[i], j) ? p- : p++;
    }
}
void calheight(int r[], int sa[], int n)
{
    ;
    ; i <= n; ++i) Rank[sa[i]] = i;
    ; i < n; height[Rank[i++]] = k)
        , j = sa[Rank[i]-]; r[i+k] == r[j+k]; k++);
}

bool IsOk(int len, int n, int aim)
{
    ;
//    for(int i=2; i<=n; i++){ //错误的!
//        if(height[i] >= len)
//            if(++cnt >= aim)
//                return true;
//    }return false;
    ; i<=n; i++){
        if(height[i] >= len){ if(++cnt >= aim) return true; }
        ;
    }return false;
}

int arr[maxn];
int main(void)
{
    int N, K;
    while(~scanf("%d %d", &N, &K)){

        ; i<N; i++)
            scanf("%d", &arr[i]);

        da(arr, sa, N+, );
        calheight(arr, sa, N);

        , R = N, ans = -;
        while(L <= R){
            );
            ;
            ;
        }
        ans==-? puts(") : printf("%d\n", ans);
    }
    ;
}

题目单个元素的值能达到 1e6 这么大,数组按这个开还勉强OK,但是这里还是要学学离散化的姿势!

离散化版:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
;
struct st{
    int ord, val;
    bool operator < (const st &rhs) const {
        return this->val < rhs.val;
    };
}arr[maxn];

int sa[maxn], s[maxn], wa[maxn], Ws[maxn], wv[maxn], wb[maxn];
int Rank[maxn], height[maxn];

bool cmp(int r[], int a, int b, int l){ return r[a] == r[b] && r[a+l] == r[b+l]; }
void da(int r[], int sa[], int n, int m)
{
    int i, j, p, *x = wa, *y = wb;
    ; i < m; ++i) Ws[i] = ;
    ; i < n; ++i) Ws[x[i]=r[i]]++;
    ; i < m; ++i) Ws[i] += Ws[i-];
    ; i >= ; --i) sa[--Ws[x[i]]] = i;
    , p = ; p < n; j *= , m = p)
    {
        , i = n - j; i < n; ++i) y[p++] = i;
        ; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
        ; i < n; ++i) wv[i] = x[y[i]];
        ; i < m; ++i) Ws[i] = ;
        ; i < n; ++i) Ws[wv[i]]++;
        ; i < m; ++i) Ws[i] += Ws[i-];
        ; i >= ; --i) sa[--Ws[wv[i]]] = y[i];
        , x[sa[]] = , i = ; i < n; ++i)
            x[sa[i]] = cmp(y, sa[i-], sa[i], j) ? p- : p++;
    }
}
void calheight(int r[], int sa[], int n)
{
    ;
    ; i <= n; ++i) Rank[sa[i]] = i;
    ; i < n; height[Rank[i++]] = k)
        , j = sa[Rank[i]-]; r[i+k] == r[j+k]; k++);
}

bool IsOk(int len, int n, int aim)
{
    ;
    ; i<=n; i++){
        if(height[i] >= len)
            { if(++cnt >= aim) return true; }
        ;
    }return false;
}

int r[maxn];
int main(void)
{
    int N, K;
    while(~scanf("%d %d", &N, &K)){
        ; i<N; i++){
            scanf("%d", &arr[i].val);
            arr[i].ord = i;
        }

        ;
        sort(arr, arr+N);
        ; i<N; i++)
             && arr[i].val == arr[i-].val) r[arr[i].ord] = num; ///注意相等的时候如何处理
            else r[arr[i].ord] = ++num;

        da(r, sa, N+, num+);
        calheight(r, sa, N);

        , R = N, ans = -;
        while(L <= R){
            );
            ;
            ;
        }
        ans==-? puts(") : printf("%d\n", ans);
    }
    ;
}

POJ 3261 Milk Patterns ( 后缀数组 && 出现k次最长可重叠子串长度 )的更多相关文章

  1. POJ 3261 Milk Patterns 后缀数组求 一个串种 最长可重复子串重复至少k次

    Milk Patterns   Description Farmer John has noticed that the quality of milk given by his cows varie ...

  2. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

  3. POJ 3261 Milk Patterns(后缀数组+单调队列)

    题意 找出出现k次的可重叠的最长子串的长度 题解 用后缀数组. 然后求出heigth数组. 跑单调队列就行了.找出每k个数中最小的数的最大值.就是个滑动窗口啊 (不知道为什么有人写二分,其实写啥都差不 ...

  4. poj 3261 Milk Patterns 后缀数组 + 二分

    题目链接 题目描述 给定一个字符串,求至少出现 \(k\) 次的最长重复子串,这 \(k\) 个子串可以重叠. 思路 二分 子串长度,据其将 \(h\) 数组 分组,判断是否存在一组其大小 \(\ge ...

  5. POJ3261 Milk Patterns —— 后缀数组 出现k次且可重叠的最长子串

    题目链接:https://vjudge.net/problem/POJ-3261 Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Tot ...

  6. POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7586   Accepted: 3448 Cas ...

  7. POJ 3261 Milk Patterns 【后缀数组 最长可重叠子串】

    题目题目:http://poj.org/problem?id=3261 Milk Patterns Time Limit: 5000MS Memory Limit: 65536K Total Subm ...

  8. poj3261 Milk Patterns 后缀数组求可重叠的k次最长重复子串

    题目链接:http://poj.org/problem?id=3261 思路: 后缀数组的很好的一道入门题目 先利用模板求出sa数组和height数组 然后二分答案(即对于可能出现的重复长度进行二分) ...

  9. poj 3261 Milk Patterns(后缀数组)(k次的最长重复子串)

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7938   Accepted: 3598 Cas ...

随机推荐

  1. 【HANA系列】SAP HANA ODBC error due to mismatch of version

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA ODBC er ...

  2. 【MM系列】SAP MR21修改标准价

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]在SAP里查看数据的方法   前言部 ...

  3. 【ABAP系列】SAP ABAP 关于BAPI的EXTENSIONIN 一点解释

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 关于BAPI的 ...

  4. Java多线程学习——知识点积累

    开启多线程时,每一个线程都拥有自己的工作空间,每个工作空间都单独的和主存打交道. 并发的概念:多个线程同时操作同一个对象 当产生并发时,如果从工作空间写入数据到内存的线程时间片用完了,其他线程再从主存 ...

  5. 华硕RT-AC86U路由器 AP模式实现多路由器组网,扩展主路由器的无线网范围

    描述: 宽带拨号上网的路由器为 TP-LINK  TL-WAR1200L,由于室内空间大,遂在此路由器下接入一个 华硕RT-AC86U路由器: 配置使该 华硕路由器与 TP-LINK 路由器的网段相同 ...

  6. 获取kafka最新offset-java

    之前笔者曾经写过通过scala的方式获取kafka最新的offset 但是大多数的情况我们需要使用java的方式进行获取最新offset scala的方式可以参考: http://www.cnblog ...

  7. nrm安装与配置

    nrm安装与配置:https://blog.csdn.net/anway12138/article/details/79455224

  8. 【转】Hadoop 1.x中fsimage和edits合并实现

    在NameNode运行期间,HDFS的所有更新操作都是直接写到edits中,久而久之edits文件将会变得很大:虽然这对NameNode运行时候是没有什么影响的,但是我们知道当NameNode重启的时 ...

  9. ASP.NET的面包屑导航控件、树形导航控件、菜单控件

    原文:http://blog.csdn.net/pan_junbiao/article/details/8579293 ASP.NET的面包屑导航控件.树形导航控件.菜单控件. 1. 面包屑导航控件— ...

  10. windows和linux安装rabbitmq

    一.windows安装rabbitmq 1.安装erlang 点击进入官网下载:http://erlang.org/download/ 2.安装rabbitmq 点击进入官网下载:http://www ...