题意 : 给出一个长度为 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. UrlConnection发送http请求 中文乱码解决

    中文乱码 DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream()); //dos.writeBytes(jsonD ...

  2. php php-fpm、nginx和js

    1 php-fpm是什么 php-fpm是php fastCGI process manager的缩写.它是php的进程管理器,对每个请求的处理都是一个进程. php-fpm管理了一个进程池,假如进程 ...

  3. mysql定时任务/mysql作业

    转自:https://www.jb51.net/article/138569.htm 详细参考:https://www.cnblogs.com/qlqwjy/p/7954175.html(事件& ...

  4. HNUSTOJ-1690 千纸鹤

    1690: 千纸鹤 时间限制: 1 Sec  内存限制: 128 MB提交: 992  解决: 296[提交][状态][讨论版] 题目描述  圣诞节快到了,校园里到处弥漫着粉红色的气息.又是一个情侣秀 ...

  5. 卸载OpenIV

    最近把 GTA5 卸载了,于是也想把用来修改 MOD 的 OpenIV 也卸载了. 结果在设置中,进行卸载的时候,弹出这个窗口 解决方案 1.首先打开 文件所在位置 2.右键,选择 属性,打开文件所在 ...

  6. TMS320F28335——下载程序到flash中

    一.让CCS软件支持Flash烧写 添加F28335.cmd文件 如图屏蔽掉25335_RAM_lnk.cmd 2.支持从Flash中拷贝文件到RAM中 添加DSP2832x_MemCopy.c 在主 ...

  7. DataTable中如何去除重复的项 (获得某个字段中的不重复项)

    就是获取DataTable中某一列的值,因为从数据库中检索数据时,按照2个字段进行分组,而要获得的那一列刚好在分组这两列中,所以该列的值必然有重复,于是就想到了去除重复,有了思路以后在网上看了一些方法 ...

  8. git 中 HEAD detached from 802e836

    head指针处于游离状态,需要建立一个分支然后将它合并到master分支,最后删除那个临时分支即可. 详情参见:https://www.jianshu.com/p/fdd3c2d020d7

  9. HTML面试问题收集(1)

    1.浏览器页面有哪三层构成,分别是什么,作用是什么? 构成:结构层.表示层.行为层分别是:HTML.CSS.JavaScript 作用:HTML实现页面结构,CSS完成页面的表现与风格,JavaScr ...

  10. 【转】交换分区SWAP

    SWAP就是LINUX下的虚拟内存分区,它的作用是在物理内存使用完之后,将磁盘空间(也就是SWAP分区)虚拟成内存来使用. 它和Windows系统的交换文件作用类似,但是它是一段连续的磁盘空间,并且对 ...