| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
Re:NlogN方法In Reply To:同问 这题应该怎么做啊 (非暴力方法) Posted by:kantianfadai at 2008-10-03 11:28:10 开两个后缀数组 三个RMQ可以做到nlogn(反正我写的是类,想开多少都无压力)
后缀数组记录正串与反串的后缀信息
同时对应的两个RMQ分别维护这两个后缀数组的height值的区间极值
在罗穗骞论文的基础上就可以做到找到最多的重复
另一个RMQ维护字典序的区间极值(利用正串的后缀数组的rank值维护)
这样在找到最多的重复的基础上同时保证了字典序最小
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define Maxn 100100
class Suffix_array
{
private:
int wa[Maxn],wb[Maxn],ws[Maxn],wv[Maxn];
bool cmp(int *r,const int &a,const int &b,const int &j)
{
return (r[a]==r[b] && r[a+j]==r[b+j]);
}
public:
int sa[Maxn],rank[Maxn],height[Maxn];
void Build_Sa(char *r,int len,int m=Maxn)
{
len++;
int *x=wa,*y=wb,i,j,p;
memset(ws,0,sizeof ws);
for(int i=0;i<len;i++) ws[x[i]=r[i]]++;
for(int i=1;i<m;i++) ws[i]+=ws[i-1];
for(int i=len-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=0;p<len;j*=2,m=p)
{
for(p=0,i=len-j;i<len;i++) y[p++]=i;
for(i=0;i<len;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<len;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<len;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=len-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
swap(x,y);
for(i=1,p=1,x[sa[0]]=0;i<len;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
}
void Build_H(char *r,const int &len)
{
int i,k=0;
for(i=1;i<=len;i++) rank[sa[i]]=i;
for(i=0;i<len;height[rank[i++]]=k)
for(k?k--:0;r[i+k]==r[sa[rank[i]-1]+k];k++);
}
};
class RMQ //st
{
private:
int LOG[Maxn];
int POW[20];
int dp[Maxn][20];
public:
RMQ()
{
for(int i=0,l=1;i<20;i++,l*=2) POW[i]=l;
LOG[0]=-2147483647;
int cur=0,Next=1;
for(int i=1;i<Maxn;i++)
{
if(i==POW[Next]) cur++,Next++;
LOG[i]=cur;
}
}
void Build(int *d,const int &len)
{
memset(dp,127,sizeof dp);
for(int i=0;i<=len;i++) dp[i][0]=d[i];
for(int i=1,l=2;l<=len+1;i++,l*=2)
for(int j=0;j<=len;j++)
{
dp[j][i]=dp[j][i-1];
if (j+l/2<=len) dp[j][i]=min(dp[j][i-1],dp[j+l/2][i-1]);
}
}
int Query(int l,int r)
{
if(l>r) l^=r^=l^=r;
return min(dp[l][LOG[r-l+1]],dp[r-POW[LOG[r-l+1]]+1][LOG[r-l+1]]);
}
};
char str[Maxn+1],inv_str[Maxn+1];
int Readin()
{
memset(str,0,sizeof str);
memset(inv_str,0,sizeof inv_str);
gets(str);
int len=strlen(str);
if(str[0]=='#') return EOF;
for(int i=0;i<len;i++) inv_str[i]=str[len-1-i];
return len;
}
Suffix_array s,inv_s;
RMQ S,rank_S,inv_S;
int start,_lenth;
bool BREAK(int &cases,int &lenth)
{
lenth=Readin();
if(lenth==EOF) return false;
return true;
}
inline int Calculate(const int &p1,const int &p2,int *rank,RMQ &S)
{
int pl=rank[p1],pr=rank[p2];
if(pl<pr) pl++;
else pr++;
return S.Query(pl,pr);
}
int main()
{
int lenth;
int cases=1;
int Maxtimes=1,L=1,p;
while(BREAK(cases,lenth))
{
Maxtimes=1;
L=1;
p=0;
printf("Case %d: ",cases++);
s.Build_Sa(str,lenth);
s.Build_H(str,lenth);
S.Build(s.height,lenth);
inv_s.Build_Sa(inv_str,lenth);
inv_s.Build_H(inv_str,lenth);
rank_S.Build(s.rank,lenth-1);
inv_S.Build(inv_s.height,lenth);
for(int l=1;l<lenth;l++)
{
for(int i=0;i+l<lenth;i+=l)
{
int tmp,times,left,right,tmp2;
tmp=Calculate(i,i+l,s.rank,S);
tmp2=Calculate(lenth-1-i,lenth-1-i-l,inv_s.rank,inv_S);
times=tmp/l+1;
left=max(0,i-(l-tmp%l));
if(times<Maxtimes-1 || (times==Maxtimes-1 && Calculate(left,left+l,s.rank,S)<l) || left==i) continue;
if(Calculate(left,left+l,s.rank,S)>=l && left!=i)
{
times++;
//i-tmp+1~left
tmp=s.sa[rank_S.Query(i-tmp2+1,left)];
}
else tmp=s.sa[rank_S.Query(i-tmp2+1,i)];
if(Maxtimes==times)
{
if(s.rank[tmp]<s.rank[start])
{
start=tmp;
_lenth=l*Maxtimes;
}
}
else
{
start=tmp,Maxtimes=times;
_lenth=l*Maxtimes;
}
}
}
if(Maxtimes==1)
{
char Min='z';
for(int i=0;i<lenth;i++) Min=Min<str[i]?Min:str[i];
printf("%c\n",Min);
}
else
{
for(int i=start;i<start+_lenth;i++)
printf("%c",str[i]);
printf("\n");
}
}
return 0;
}
Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator