POJ 3693

题意:给定一个字符串,求其中一个由循环子串构成且循环次数最多的一个子串,有多个就输出最小字典序的。

题解:后缀数组+RMQ。

   1、枚举循环串的长度ll,然后如果它出现了两次,那么它一定会覆盖s[0],s[ll],s[ll*2].....这些点中相邻的两个。

   2、再枚举它覆盖的最左边的那个s[ll*i],通过rmq求s[ll*i]与s[ll*i+ll]的最长公共前缀K,可以看出,从[ll*i,ll*i+ll+K]这个区间内,s[ll*i,ll*(i+1)-1]重复出现了K/ll+1次。

   3、在第2步中,还有可能就是循环串并不是从ll*i开始的,所以要枚举它前面[ll*(i-1)+1,ll*i-1]位置的情况。

View Code
  1 #include<cstdio>

  2 #include<cstring>

  3 #include<algorithm>

  4 #include<cmath>

  5 using namespace std;

  6 const int N=100005;

  7 char s[N];

  8 int n,sa[N],height[N],rank[N],tmp[N],top[N];

  9 void makesa()

 10 {

 11     int i,j,len,na;

 12     na=max(256,n);

 13     memset(top,0,sizeof(top));

 14     for(i=0;i<n;i++)top[rank[i]=(s[i]&0xff)]++;

 15     for(i=1;i<na;i++)top[i]+=top[i-1];

 16     for(int i=0;i<n;i++)sa[--top[rank[i]]]=i;

 17     for(len=1;len<n;len<<=1)

 18     {

 19         for(i=0;i<n;i++)

 20         {

 21             j=sa[i]-len;

 22             if(j<0)j+=n;

 23             tmp[top[rank[j]]++]=j;

 24         }

 25         sa[tmp[top[0]=0]]=j=0;

 26         for(i=1;i<n;i++)

 27         {

 28             if(rank[tmp[i]]!=rank[tmp[i-1]]||rank[tmp[i]+len]!=rank[tmp[i-1]+len])

 29                 top[++j]=i;

 30             sa[tmp[i]]=j;

 31         }

 32         memcpy(rank,sa,sizeof(int)*n);

 33         memcpy(sa,tmp,sizeof(int)*n);

 34         if(j>=n-1)

 35             break;

 36     }

 37 }

 38 void lcp()

 39 {

 40     int i,j,k;

 41     for(j=rank[height[i=k=0]=0];i<n-1;i++,k++)

 42     {

 43         while(k>=0&&s[i]!=s[sa[j-1]+k])

 44             height[j]=k--,j=rank[sa[j]+1];

 45     }

 46 }

 47 int st[40][N];

 48 void initrmq()

 49 {

 50     int i,j,k,sk;

 51     for(i=0;i<n;i++)st[0][i]=height[i];

 52     for(i=1,k=2;k<n;i++,k<<=1)

 53     {

 54         for(j=0,sk=(k>>1);j<n;j++,sk++)

 55         {

 56             st[i][j]=st[i-1][j];

 57             if(sk<n&&st[i][j]>st[i-1][sk])

 58             {

 59                 st[i][j]=st[i-1][sk];

 60             }

 61         }

 62     }

 63 }

 64 int lg[N];

 65 int query(int x,int y)

 66 {

 67     if(x>y)

 68         swap(x,y);

 69     x++;

 70     int b=lg[y-x+1];

 71     return min(st[b][x],st[b][y-(1<<b)+1]);

 72 }

 73 struct data

 74 {

 75     int len,r,pos;

 76     data(){}

 77     data(int _len,int _r,int _pos){len=_len;r=_r;pos=_pos;}

 78     bool operator<(const data &ne)const

 79     {

 80         if(r!=ne.r)

 81             return r<ne.r;

 82         return rank[pos]>rank[ne.pos];

 83     }

 84 };

 85 int main()

 86 {

 87     int ca=0;

 88     lg[0]=-1;

 89     for(int i=1;i<N;i++){

 90         lg[i]=(i&(i-1))?lg[i-1]:(lg[i-1]+1);

 91     }

 92     while(gets(s),strcmp(s,"#")!=0)

 93     {

 94         n=strlen(s)+1;

 95         makesa();lcp();initrmq();

 96         int a,b;

 97         data ans(1,1,0);

 98         for(int ll=1;ll<n;ll++)

 99         {

100             for(int i=0;i+ll<n;i+=ll)

101             {

102                 int t,r,k=query(rank[i],rank[i+ll]);

103                 r=k/ll+1;

104                 t=i-ll+k%ll;

105                 if(t>=0&&k%ll!=0&&query(rank[t],rank[t+ll])>=k)

106                 {

107                     r++;

108                     while(t>=0&&t>i-ll&&query(rank[t],rank[t+ll])>=k)

109                     {

110                         data tp(ll,r,t);

111                         if(ans<tp)

112                             ans=tp;

113                         t--;

114                     }

115                 }

116                 else

117                 {

118                     data tp(ll,r,i);

119                     if(ans<tp)

120                         ans=tp;

121                 }

122             }

123         }

124         s[ans.pos+ans.len*ans.r]='\0';

125         printf("Case %d: %s\n",++ca,s+ans.pos);

126     }

127     return 0;

128 }

你可能感兴趣的:(poj)