后缀数组练习题

Milk Patterns

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 17079   Accepted: 7553
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, he discovered that although he can‘t predict the quality of milk from one day to the next, there are some regular patterns in the daily milk quality.

To perform a rigorous study, he has invented a complex classification scheme by which each milk sample is recorded as an integer between 0 and 1,000,000 inclusive, and has recorded data from a single cow over N (1 ≤ N ≤ 20,000) days. He wishes to find the longest pattern of samples which repeats identically at least K (2 ≤ KN) times. This may include overlapping patterns -- 1 2 3 2 3 2 3 1 repeats 2 3 2 3 twice, for example.

Help Farmer John by finding the longest repeating subsequence in the sequence of samples. It is guaranteed that at least one subsequence is repeated at least K times.

Input

Line 1: Two space-separated integers: N and K
Lines 2..N+1: N integers, one per line, the quality of the milk on day i appears on the ith line.

Output

Line 1: One integer, the length of the longest pattern which occurs at least K times

Sample Input

8 2
1
2
3
2
3
2
3
1

Sample Output

4

求最长可重复至少出现k次的子串长度
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+88;
const int M=2e4+88;
int wa[N],wv[N],ws[N];
int sa[M],rank[M],wb[M],height[M],num[M];
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 n,int m){
    int *x=wa,*y=wb;
    for(int i=0;i<m;++i) ws[i]=0;
    for(int i=0;i<n;++i) ++ws[x[i]=r[i]];
    for(int i=1;i<m;++i) ws[i]+=ws[i-1];
    for(int i=0;i<n;++i) sa[--ws[x[i]]]=i;
    int p=1;
    for(int j=1;p<n;j<<=1,m=p) {
        p=0;
        for(int i=n-j;i<n;++i) y[p++]=i;
        for(int i=0;i<n;++i) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(int i=0;i<n;++i) wv[i]=x[y[i]];
        for(int i=0;i<m;++i) ws[i]=0;
        for(int i=0;i<n;++i) ++ws[wv[i]];
        for(int i=1;i<m;++i) ws[i]+=ws[i-1];
        for(int i=n-1;i>=0;--i) sa[--ws[wv[i]]]=y[i];
        swap(x,y),x[sa[0]]=0,p=1;
        for(int i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    for(int i=1;i<n;++i) rank[sa[i]]=i;
    int k=0;
    for(int i=0;i<n-1;height[rank[i++]]=k){
        if(k) --k;
        for(int j=sa[rank[i]-1];r[i+k]==r[j+k];++k);
    }
}
bool Ju(int k,int lim,int ci){
    int cnt=0;
    for(int i=2;i<=lim;++i)
    {
    if(height[i]>=k) ++cnt;
    else cnt=0;
    if(cnt>=ci) return true;
    }
    return false;
}
int main(){
    int ans,l,r,n,k,x,maxx=0;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;++i) {
        scanf("%d",num+i);
        ++num[i];
        maxx=max(maxx,num[i]);
    }
    num[n]=0;
    da(num,n+1,maxx+1);
    l=1,r=n;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(Ju(mid,n,k-1)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
}

原文地址:https://www.cnblogs.com/mfys/p/8438460.html

时间: 2024-08-02 19:43:40

后缀数组练习题的相关文章

BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

POJ 1226后缀数组:求出现或反转后出现在每个字符串中的最长子串

思路:这题是论文里的最后一道练习题了,不过最后一题竟然挺水的. 因为求的是未反转或者反转后,最长公共子串. 刚开始还真不知道怎么构建连接成一个字符串,因为需要有反转嘛! 但是其实挺简单的,把未反转的和反转后的字符串都连起来,中间用未出现过的字符隔开就行了!然后未反转的和反转的在同一组. 二分枚举最长的公共前缀长度,然后统计看看这个最长的长度在不在所有的组里,如果在就符合-- #include<iostream> #include<cstdio> #include<cstrin

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

hdu5769--Substring(后缀数组)

题意:求含有某个字母的某个字符串的不同子串的个数 题解:后缀数组,记录每个位置距离需要出现的字母的距离就可以了.因为不太了解后缀模版卡了一会,还是很简单的. 记住sa和height数组都是1-n的下标. //后缀数组 #include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll;

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

【tyvj1860】后缀数组

描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串.后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0你的任务就是求出SA和height这两个数组.字符串长度<=200000 输入格式 一行,为描述中的字符串(仅会出现小写

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

hdu 4416 Good Article Good sentence(后缀数组&amp;思维)

Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 649 Problem Description In middle school, teachers used to encourage us to pick up pre