POJ

来源:互联网 发布:数据对比分析的方法 编辑:程序博客网 时间:2024/06/17 00:35

题意:给一个字符串,求重复次数最多的连续重复子串,如有多解,输出字典序最小的。






思路:

先后缀数组求height,然后考虑分块,枚举重复子串的长度l,则每个重复子串必定经过(0,l,2*l,3*l.....)中的一个点,然后对每两个相邻的这样的点求LCP(i,i+L),这是向后匹配能匹配多少,如果忽略i前面的部分,答案是LCP(i,i+L)/L+1,但是如何计算i前面的部分呢?如果LCP(i,i+L)%L>0,说明有剩余left,而剩余的要能和前面的匹配,则有RMQ(i-(L-left),i-(L-left)+L)>lcp才行。


经过上面的操作,能够求出最大重复次数,然后我们能达到最大次数的所有L,再遍历一遍求出最小Rank,即是字典序最小的串。注意这步操作不能在上面求最大重复次数的时候统一求,因为我们虽然能求出最大重复次数,但是却不能保证字典序最小的串在(L,2*L,3*L...)处开始,比如aababababa,此时答案是abababab,而不是babababa。



这个题细节、证明、技巧多,思维量大,写了半天时间。

还有就是最好去HDU - 2459提交下这个题,因为POJ这个题数据太水


感觉这个题要比UVA - 10829难,不过思路都是对L分块。

#include <cstdio>#include <algorithm>#include <iostream>#include <vector>#include <cstring>#include <string>#include <cmath>#include <map>#include <queue>#include <set>#include <bitset>#include <stack>#include <sstream>#define IO ios::sync_with_stdio(false),cin.tie(0);#define pb push_back#define pii pair<int,int>#define mp make_pair#define rep(i,a,b) for(int i=a;i<=b;i++)#define dep(i,a,b) for(int i=a;i>=b;i--)#define mem(a,b) memset(a,b,sizeof(a))#define debug(x) cout<<#x<<" = "<<"["<<x<<"]"<<endl;#define lson id<<1,l,mid#define rson id<<1|1,mid+1,rtypedef long long ll;using namespace std;const double eps=1e-7;const int MOD=1e9+7;const ll INFLL=0x3f3f3f3f3f3f3f3f;const int INF=0x3f3f3f3f;const int MAXN=1e5+5;int sa[MAXN], Rank[MAXN], height[MAXN];int wa[MAXN], wb[MAXN], wv[MAXN], wd[MAXN];char s[MAXN];int cmp(int *r, int a, int b, int l) {    return r[a] == r[b] && r[a+l] == r[b+l];}void da(char *r, int n, int m=128) {         //  倍增算法 r为待匹配数组  n为总长度 要+1 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 ++;        }    }}void calHeight(char *r, int n) {          //  求height数组。n不用+1    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 ++);    }}int dp[MAXN][50];void RMQ_init(int n) {    for(int i=1; i<=n; i++) 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 RMQ(int L,int R) {    int k=0,t=L;    L=min(Rank[L],Rank[R]);    R=max(Rank[t],Rank[R]);    while((1<<(k+1))<=R-L) k++;    return min(dp[L+1][k],dp[R-(1<<k)+1][k]);}int le[MAXN];int main() {    int cas=1;    while(~scanf("%s",s)) {        if(s[0]=='#')break;        int len=strlen(s);        da(s,len+1),calHeight(s,len);        RMQ_init(len);        int ans=1,cnt=0;        for(int l=1; l*2<=len; l++) {            for(int i=0; i+l<len; i+=l) {                if(s[i]==s[i+l]) {                    int lcp=RMQ(i,i+l);                    int repeat=lcp/l+1,left=lcp%l;                    if(left&&i-(l-left)>=0&&RMQ(i-(l-left),i+left)>lcp)repeat++;                    if(ans<repeat) {                        ans=repeat;                        cnt=0;                        le[cnt++]=l;                    }else if(ans==repeat){                        le[cnt++]=l;                    }                }            }        }        cnt=unique(le,le+cnt)-le;        int loc=1,ansl=1,flag=0;        for(int i=0;i<len;i++){            for(int j=0;j<cnt;j++){                if(RMQ(i,i+le[j])/le[j]+1==ans){                    if(loc>Rank[i]||!flag){                        flag=1;                        loc=Rank[i];ansl=le[j];                    }                }            }        }        printf("Case %d: ",cas++);        for(int i=sa[loc];i<sa[loc]+ansl*ans;i++)printf("%c",s[i]);        puts("");    }}






原创粉丝点击