HDU4080Stammering Aliens(后缀数组+二分)

However, all efforts to decode their messages have failed so far because, as luck would have it, they have stumbled upon a race of stuttering aliens! Her team has found out that, in every long enough message, the most important words appear repeated a certain number of times as a sequence of consecutive characters, even in the middle of other words. Furthermore, sometimes they use contractions in an obscure manner. For example, if they need to say bab twice, they might just send the message babab, which has been abbreviated because the second b of the first word can be reused as the first b of the second one. 
Thus, the message contains possibly overlapping repetitions of the same words over and over again. As a result, Ellie turns to you, S.R. Hadden, for help in identifying the gist of the message. 
Given an integer m, and a string s, representing the message, your task is to find the longest substring of s that appears at least m times. For example, in the message baaaababababbababbab, the length-5 word babab is contained 3 times, namely at positions 5, 7 and 12 (where indices start at zero). No substring appearing 3 or more times is longer (see the first example from the sample input). On the other hand, no substring appears 11 times or more (see example 2). In case there are several solutions, the substring with the rightmost occurrence is preferred (see example 3).

InputThe input contains several test cases. Each test case consists of a line with an integer m (m >= 1), the minimum number of repetitions, followed by a line containing a string s of length between m and 40 000, inclusive. All characters in s are lowercase characters from "a" to "z". The last test case is denoted by m = 0 and must not be processed. 
OutputPrint one line of output for each test case. If there is no solution, output none; otherwise, print two integers in a line, separated by a space. The first integer denotes the maximum length of a substring appearing at least m times; the second integer gives the rightmost starting position of this substring. 
Sample Input

3
baaaababababbababbab
11
baaaababababbababbab
3
cccccc
0

Sample Output

5 12
none
4 2

题意:

求字符串里面出现的子序列中出现超过m次的最长子序列(可交叉),没有输出none,有则输出长度,和最后一次出现的位置。

思路:

求出后缀数组,二分长度,得到长度,至于最后一次的位置,需要把每个位置枚举一下,即大于Mid的ht[i],对应着的sa[i],和sa[i-1]。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
using namespace std;
const int maxn=40010;
char ch[maxn]; int m;
int max(int x,int y){if(x>y) return x;return y;}
struct SA
{
    int Rank[maxn],sa[maxn],tsa[maxn],cntA[maxn],cntB[maxn],A[maxn],B[maxn];
    int ht[maxn],N;
    void get_sa()
    {
        N=strlen(ch+1);
        for(int i=0;i<=300;i++) cntA[i]=0;
        for(int i=1;i<=N;i++) cntA[ch[i]]++;
        for(int i=1;i<=300;i++) cntA[i]+=cntA[i-1];
        for(int i=N;i>=1;i--) sa[cntA[ch[i]]--]=i;
        Rank[sa[1]]=1;
        for(int i=2;i<=N;i++) Rank[sa[i]]=Rank[sa[i-1]]+(ch[sa[i]]==ch[sa[i-1]]?0:1);
        for(int l=1;Rank[sa[N]]<N;l<<=1){
            for(int i=1;i<=N;i++) cntA[i]=cntB[i]=0;
            for(int i=1;i<=N;i++) cntA[A[i]=Rank[i]]++;
            for(int i=1;i<=N;i++) cntB[B[i]=i+l<=N?Rank[i+l]:0]++;
            for(int i=1;i<=N;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
            for(int i=N;i>=1;i--) tsa[cntB[B[i]]--]=i;
            for(int i=N;i>=1;i--) sa[cntA[A[tsa[i]]]--]=tsa[i];
            Rank[sa[1]]=1;
            for(int i=2;i<=N;i++) Rank[sa[i]]=Rank[sa[i-1]]+(A[sa[i]]==A[sa[i-1]]&&B[sa[i]]==B[sa[i-1]]?0:1);
        }
    }
    void get_ht()
    {
        for(int i=1,j=0;i<=N;i++){
            if(j) j--;
            while(ch[i+j]==ch[sa[Rank[i]-1]+j]) j++;
            ht[Rank[i]]=j;
        }
    }
    int check(int L)
    {
        int cnt=1,tmppos=0,pos=0;
        for(int i=1;i<=N;i++){
            if(ht[i]<L) cnt=1,tmppos=0;
            else cnt++,tmppos=max(tmppos,max(sa[i],sa[i-1]));
            if(cnt>=m) pos=max(tmppos,pos);
        }  return pos;
    }
    void solve()
    {
        //for(int i=1;i<=N;i++) printf("%d ",sa[i]);printf("\n");
        //for(int i=1;i<=N;i++) printf("%d ",ht[i]);printf("\n");
        int L=0,R=N,ans=0,tmp,anspos=0;
        while(L<=R){
            int Mid=(L+R)>>1;
            tmp=check(Mid);
            if(tmp) {
               ans=Mid;anspos=tmp; L=Mid+1;
            } else R=Mid-1;
        }
        if(ans==0) printf("none\n");
        else printf("%d %d\n",ans,anspos-1);
    }
}Sa;
int main()
{
    int i,j,k;
    while(~scanf("%d",&m)&&m){
         scanf("%s",ch+1);
         if(m==1){
             printf("%d 0\n",strlen(ch+1));
             continue;
         }
         Sa.get_sa();
         Sa.get_ht();
         Sa.solve();
    } return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/8166064.html

时间: 2024-11-09 02:00:24

HDU4080Stammering Aliens(后缀数组+二分)的相关文章

UVA 12206 - Stammering Aliens(后缀数组)

UVA 12206 - Stammering Aliens 题目链接 题意:给定一个序列,求出出现次数大于m,长度最长的子串的最大下标 思路:后缀数组,搞出height数组后,利用二分去查找即可 这题之前还写过hash的写法也能过,不过写后缀数组的时候,犯了一个傻逼错误,把none输出成node还一直找不到...这是刷题来第二次碰到这种逗比错误了,还是得注意.. 代码: #include <cstdio> #include <cstring> #include <algori

POJ 3882 Stammering Aliens 后缀数组height应用

题目来源:POJ 3882 Stammering Aliens 题意:给你m一个一个字符串 求至少出现m次的最长字符串 可以在字符串中重叠出现 思路:二分长度l 然后从height数组中找长度大于等于l的前缀 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 40010; char s[maxn]; int sa[maxn]; i

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

BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) --------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace std; typedef long long

hdu 5008(2014 ACM/ICPC Asia Regional Xi&#39;an Online ) Boring String Problem(后缀数组&amp;二分)

Boring String Problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 219    Accepted Submission(s): 45 Problem Description In this problem, you are given a string s and q queries. For each que

【bzoj4310】跳蚤 后缀数组+二分

题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个.他称其为“魔力串”. 现在他想找一个最优的分法让“魔力串”字典序最小. 输入 第一行一个整数 k. 接下来一个长度不超过 105 的字符串 S. 输出 输出一行,表示字典序最小的“魔力串”. 样例输入 13 bcbcbacbbbbbabbacbcb

WHU---1084 - 连续技 (后缀数组+二分)

Description 不管是什么武功,多少都会有一或两个连续技多次出现,这些连续技常常是发明该武功的人的习惯性动作,如果这些动作被对手分析出来了,就很容易被对手把握住先机.比如松风剑谱里面有一式叫做迎风傲骨是如下的动作: 劈 刺 削 刺 削 踢 刺 削 刺 削 很明显 刺-削 这个连续动作出现了4次,而 刺-削-刺-削 这个连续动作则出现了两次. 现在刘白宇弄到了一本魔教的掌法,想让你帮忙来分析其中最长的且出现尽量多的连续技,当然,他不好意思麻烦你太久,只想让你告诉它这个连续技有多长并且出现了

poj 3261 Milk Patterns 后缀数组+二分

1 /*********************************************************** 2 题目: Milk Patterns(poj 3261) 3 链接: http://poj.org/problem?id=3261 4 题意: 给一串数字,求这些数字中公共子串个数大于k的 5 最长串. 6 算法: 后缀数组+二分 7 ***********************************************************/ 8 #incl

POJ1743---Musical Theme(后缀数组+二分)

Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of music