您的位置:首页 > 其它

HDU2459 后缀数组+RMQ

2016-01-24 16:04 183 查看
题目大意:

在原串中找到一个拥有连续相同子串最多的那个子串

比如dababababc中的abababab有4个连续的ab,是最多的

如果有同样多的输出字典序最小的那个

这里用后缀数组解决问题:

枚举连续子串的长度l , 那么从当前位置0出发每次递增l,拿 i 和 i+l 开头的后缀求一个前缀和val , 求解依靠RMQ 得到区间 rank(i),rank(i+l)

那么连续的子串个数应该是val/l+1

但是由于你不一定是从最正确的位置出发,那么我们就需要不断将这个i往前推l位,直到某一位字符不匹配,推移的过程中,可能与形成连续串多出的

部分形成一个新的子串,那么个数应该加1,且不断更新推移过程中的rank值,尽量取到rank值小的开头的字符串

#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 100010;
int r
, sa
, _rank
, height
;
int wa
, wb
, wv
, wsf
;
int 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 *sa , int n , int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++)wsf[i]=0;
for(i=0;i<n;i++)wsf[x[i]=r[i]]++;
for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
for(i=n-1;i>=0;i--) sa[--wsf[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++) wsf[i]=0;
for(i=0;i<n;i++) wsf[wv[i]]++;
for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
for(i=n-1;i>=0;i--) sa[--wsf[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++;
}
return;
}
void callHeight(int *r , int *sa , int n)
{
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++);
return;
}

int dp[N<<1][18] , n;
char s
;
void ST()
{
memset(dp , 0x3f , sizeof(dp));
for(int i=1 ; i<=n ; i++)dp[i][0]=height[i];
for(int k=1 ; (1<<k)<=n ; k++){
for(int i=1 ; i<=n ; i++){
dp[i][k] = min(dp[i][k-1] , dp[i+(1<<(k-1))][k-1]);
}
}
}
int RMQ(int s , int t)
{
int d = t-s+1;
int k = (int)log2(d*1.0);
// cout<<s<<" "<<t<<" "<<k<<" "<<t-(1<<k)+1<<endl;
return min(dp[s][k] , dp[t-(1<<k)+1][k]);
}
int RMQPOS(int x , int y)
{
//  cout<<"cal pos: "<<x<<" "<<y<<" ";
x = _rank[x] , y = _rank[y];
if(x>y){int t=x;x=y,y=t;}
// cout<<x<<" "<<y<<" "<<RMQ(x+1,y)<<" ";
return RMQ(x+1,y);
}
void solve(int &mxTime , int &ansl , int &ansLf)
{
ansl = ansLf = mxTime = 0;
for(int l=1 ; l<=n/2 ; l++) {//最外层循环节长度
for(int i=0 ; i+l<n ; i+=l){
int mxl = RMQPOS(i , i+l);
int time = mxl/l+1;

int del = time*l-mxl , curpos=i , mxRank=_rank[i];
int t;
for(t=1 ; t<l ; t++){
if(i<t || s[i-t]!=s[i+l-t]) break;
if(_rank[i-t]<mxRank){
mxRank = _rank[i-t];
curpos = i-t;
}
if(t==del){
mxRank = _rank[i-t];
curpos = i-t , time++;
}
}

if(mxTime<time||(mxTime==time&&mxRank<_rank[ansLf])) mxTime=time,ansl=time*l,ansLf=curpos;

}
}
}
int main()
{
//freopen("a.in"  , "r" , stdin);
int cas =0 ;
while(scanf("%s" , s))
{
n = strlen(s);
if(n==1 && s[0]=='#') break;
printf("Case %d: ",++cas);
for(int i=0 ; i<n ; i++) r[i] = s[i]-'a'+1;
r
=0;
da(r,sa,n+1,27);
callHeight(r,sa,n);
ST();

int mxTime , ansl , ansLf;
solve(mxTime , ansl , ansLf);
if(mxTime==1){
char minc='a';
for(int i=0 ; i<n ; i++){
minc=min(minc , s[i]);
}
printf("%c\n" , minc);
continue;
}
for(int i=0 , j=ansLf ; i<ansl ; i++,j++) printf("%c" , s[j]);
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: