poj 3693 后缀数组求重复次数最多的连续重复子串

#include<iostream>
#include<cstring>
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<algorithm>
#include<stdio.h>
#include<iomanip>

#define rep(i,n) for(int i=0;i<n;++i)
#define fab(i,a,b) for(int i=a;i<=b;++i)
#define fba(i,b,a) for(int i=b;i>=a;--i)
#define PB push_back
#define INF 0x3f3f3f3f
#define MP make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define sf scanf
#define pf printf
#define LL long long
const int N=100105;
using namespace std;
typedef pair<int,int>PII;
int wa[N],wb[N],wv[N],wd[N];
int sa[N],rank[N],height[N];
char str[N];
int a[N];
int cmp(int *r, int a, int b, int l){
    return r[a] == r[b] && r[a+l] == r[b+l];
}
//r数组的长度n从[0,n)
//求出的sa为从[1,n]
//调用时候r[n-1]=0
void da(char *r, int n, int m){          //  倍增算法 r为待匹配数组  n为总长度 m为字符范围
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i ++) wd[i] = 0;
    for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
    for(i = 1; i < m; i ++) wd[i] += wd[i-1];
    for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
    for(j = 1, p = 1; p < n; j *= 2, m = p){
        for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
        for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
        for(i = 0; i < n; i ++) wv[i] = x[y[i]];
        for(i = 0; i < m; i ++) wd[i] = 0;
        for(i = 0; i < n; i ++) wd[wv[i]] ++;
        for(i = 1; i < m; i ++) wd[i] += wd[i-1];
        for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
        for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
        }
    }
}
// 求出的 height [1,n] 对应sa中的[1,n]
// 求出的 rank [0,n-1] 对应sa中的[1,n]
// 调用时候最后添加的0不用加进去
void calHeight(char *r, int n){           //  求height数组。
    int i, j, k = 0;
    for(i = 1; i <= n; i ++) rank[sa[i]] = i;
    for(i = 0; i < n; height[rank[i++]] = k){
        for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
    }
}
/*
//为了统一,所有的下标从0开始,左闭右开!
void fix(int n){
    rep(i,n)sa[i]=sa[i+1],rank[i]--,height[i]=height[i+1];
}*/
int dp[N][30];
void init_rmq(int n){
    fab(i,1,n)dp[i][0]=height[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
}
int cas=1;
int ans[N];
int rmq(int L,int R){
    L=rank[L],R=rank[R];
    if(L>R)swap(L,R);
    L++;
    int k=0;
    while((1<<(k+1))<=R-L+1)k++;
    return min(dp[L][k],dp[R-(1<<k)+1][k]);
}
void solve(){
    int n=strlen(str);
    str[n]=0;
    da(str,n+1,200);
    calHeight(str,n);
    init_rmq(n);
    int maxv=-1;
    int cnt=0;
    for(int len=1;len<n;len++){
       for(int i=0;i+len<n;i+=len){
           int lcp=rmq(i,i+len);
           int tmp=lcp/len+1;
           int ni=i-(len-lcp%len);
           if(ni>=0&&lcp%len!=0){
               tmp=max(tmp,rmq(ni,ni+len)/len+1);
           }
           if(tmp>maxv){
               maxv=tmp;
               cnt=0;
               ans[cnt++]=len;
           }else if(tmp==maxv){
               ans[cnt++]=len;
           }
       }
    }

    //pf("cnt ");rep(i,cnt)pf("%d ",ans[i]);pf("\n");
    int len=-1,st;
    for(int i=1;i<=n&&len==-1;i++){
        rep(j,cnt){
           if(rmq(sa[i],sa[i]+ans[j])>=(maxv-1)*ans[j]){
               len=ans[j]*maxv;
               st=sa[i];
               break;
           }
        }
    }
    //pf("st %d %d\n",st,len);
    pf("Case %d: ",cas++);
    rep(i,len)putchar(str[i+st]);
    puts("");
}
int main(){
    while(~sf("%s",str)&&str[0]!=‘#‘){
        solve();
    }
    return 0;
}
时间: 2024-10-10 17:58:47

poj 3693 后缀数组求重复次数最多的连续重复子串的相关文章

POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

【POJ 3693】Maximum repetition substring 重复次数最多的连续重复子串

后缀数组的论文里的例题,论文里的题解并没有看懂,,, 求一个重复次数最多的连续重复子串,又因为要找最靠前的,所以扫的时候记录最大的重复次数为$ans$,扫完后再后从头暴力扫到尾找重复次数为$ans$的第一个子串的开头,break输出就可以了 #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1000

spoj687 后缀数组重复次数最多的连续重复子串

REPEATS - Repeats no tags A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed string t with length l>=1. For example, the string s = abaabaabaaba is a (4,3)-repeat with t = aba as its seed string. That is, the

UVA 题目11512 - GATTACA(后缀数组求出现次数最多的子串及重复次数)

The Institute of Bioinformatics and Medicine (IBM) of your country has been studying the DNA sequences of several organisms, including the human one. Before analyzing the DNA of an organism, the investigators must extract the DNA from the cells of th

Maximum repetition substring POJ - 3693(重复次数最多的连续重复子串)

这题和SPOJ - REPEATS 一样  代码改一下就好了 这个题是求这个重复子串,还得保证字典序最小 巧妙运用sa 看这个 https://blog.csdn.net/queuelovestack/article/details/53035903 很清晰 #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include&l

POJ - 2406 ~SPOJ - REPEATS~POJ - 3693 后缀数组求解重复字串问题

POJ - 2406 题意: 给出一个字符串,要把它写成(x)n的形式,问n的最大值. 这题是求整个串的重复次数,不是重复最多次数的字串 这题很容易想到用KMP求最小循环节就没了,但是后缀数组也能写 后缀数组写法放在后面那一题,SPOJ - REPEATS是求子串类型,KMP就不好处理了 这里放下处理KMP的AC代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <c

【poj3693-重复次数最多的连续重复子串】后缀数组

题意:给定一个串,长度<=10^5,求它重复次数最多的连续重复子串(输出字典序最小的那个). 例如ccabcabc,答案就是abcabc 一开始没想清楚,结果调了好久. 对于当前的L,i,i+1,x=s[i*L],y=s[(i+1)*L],找前找后,知道了最早能匹配到t0,最晚能匹配到t1,因为不知道当前的起始点是真正循环节的第几个点,所以我们要往前找L个点看看它们是不是真正的起始点. 细节就看代码吧: #include<cstdio> #include<cstdlib> #

POJ 3693 Maximum repetition substring (寻找重复次数最多的连续子串)

Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9083   Accepted: 2782 Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same conse

POJ 3693 (后缀数组) Maximum repetition substring

找重复次数最多的字串,如果有多解,要求字典序最小. 我也是跟着罗穗骞菊苣的论文才刷这道题的. 首先还是枚举一个循环节的长度L,如果它出现两次的话,一定会包含s[0], s[L], s[2L]这些相邻两个之间. 然后枚举相邻的两个,尽可能的向前和向后延伸,假设延伸长度为k,则重复次数为k / L + 1 向后延伸很自然的就是求一次LCP,这个用RMQ预处理一下就可以O(1)查询. 向前延伸就是考虑到,我们枚举的s[i*L]和s[(i+1)*L]并不一定是字串的开头,所以向前移动i - (k % i