题目:http://poj.org/problem?id=3693
题目大意:就是给你一个字符串,让你找出它的连续的重复次数最多的子串。
思路:罗穗骞论文里的题目,好题!论文地址:http://wenku.baidu.com/view/228caa45b307e87101f696a8.html
先穷举长度L,然后求长度为L的子串最多能连续出现几次。首先连续出现1次是肯定可以的,所以这里只考虑至少2次的情况。假设在原字符串中连续出现2次,记这个子字符串为S,那么S肯定包括了字符r[0],r[L],r[L*2],r[L*3],……中的某相邻的两个。所以只须看字符r[L*i]和r[L*(i+1)]往前和往后各能匹配到多远,记这个总长度为K,那么这里连续出现了K/L+1
次。最后看最大值是多少。穷举长度L的时间是n,每次计算的时间是n/L。所以整个做法的时间复杂度是O(n/1+n/2+n/3+……+n/n)=O(nlogn)。
以上摘自论文。其实我个人感觉这里的关键是怎么样O(1)匹配前面。当我们枚举 i*len 和(i+1)*len 时,有可能这两个点不是
这个重复子串的起点和终点,只是包含。设 p1 = i*len ,p2 = (i+1)*len,先算k = lcp(p1,p2),如果k%len == 0,那么这个
次数肯定就是了,不用管前面,因为前面最多 len-1 个。然后就是 != 0 的情况,怎么搞定前面?设 t = k%len,那么就是说后面多了
t 个匹配的字符,这时前面如果len - t个字符再一样,次数就要 +1,对,这也是唯一的一种次数 +1 的情况,其他情况不可能!所以,
这个时候就只需要算一下lcp(p1-(len-t),p2-(len-t)),比较一下即可。这里还有个地方需要注意:这里只能得出重复的最多次数,
以及这个次数所对应的长度 len,并不能确定位置。所以后面还要再扫描 sa 数组,根据长度和次数,把字典序最小的找出来。
自己做,枚举那里只能想到 +1 这样枚举,这样就是O(n^2)了,想不出这样 O(n*logn)的算法。。 ORZ。。
题目大意:就是给你一个字符串,让你找出它的连续的重复次数最多的子串。
思路:罗穗骞论文里的题目,好题!论文地址:http://wenku.baidu.com/view/228caa45b307e87101f696a8.html
先穷举长度L,然后求长度为L的子串最多能连续出现几次。首先连续出现1次是肯定可以的,所以这里只考虑至少2次的情况。假设在原字符串中连续出现2次,记这个子字符串为S,那么S肯定包括了字符r[0],r[L],r[L*2],r[L*3],……中的某相邻的两个。所以只须看字符r[L*i]和r[L*(i+1)]往前和往后各能匹配到多远,记这个总长度为K,那么这里连续出现了K/L+1
次。最后看最大值是多少。穷举长度L的时间是n,每次计算的时间是n/L。所以整个做法的时间复杂度是O(n/1+n/2+n/3+……+n/n)=O(nlogn)。
以上摘自论文。其实我个人感觉这里的关键是怎么样O(1)匹配前面。当我们枚举 i*len 和(i+1)*len 时,有可能这两个点不是
这个重复子串的起点和终点,只是包含。设 p1 = i*len ,p2 = (i+1)*len,先算k = lcp(p1,p2),如果k%len == 0,那么这个
次数肯定就是了,不用管前面,因为前面最多 len-1 个。然后就是 != 0 的情况,怎么搞定前面?设 t = k%len,那么就是说后面多了
t 个匹配的字符,这时前面如果len - t个字符再一样,次数就要 +1,对,这也是唯一的一种次数 +1 的情况,其他情况不可能!所以,
这个时候就只需要算一下lcp(p1-(len-t),p2-(len-t)),比较一下即可。这里还有个地方需要注意:这里只能得出重复的最多次数,
以及这个次数所对应的长度 len,并不能确定位置。所以后面还要再扫描 sa 数组,根据长度和次数,把字典序最小的找出来。
自己做,枚举那里只能想到 +1 这样枚举,这样就是O(n^2)了,想不出这样 O(n*logn)的算法。。 ORZ。。
代码如下:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 111111;
char str[MAXN];
int sa[MAXN],rank[MAXN],height[MAXN];
int t[MAXN],t2[MAXN],c[MAXN];
void cal_height(int n)
{
for(int i = 1;i <= n;i++) rank[sa[i]] = i;
int k = 0;
for(int i = 0;i < n;i++)
{
if(k) k--;
int j = sa[rank[i]-1];
while(str[i+k] == str[j+k]) k++;
height[rank[i]] = k;
}
}
void da(int n,int m)
{
int *x = t,*y = t2;
for(int i = 0;i < m;i++) c[i] = 0;
for(int i = 0;i < n;i++) c[x[i] = str[i]]++;
for(int i = 1;i < m;i++) c[i] += c[i-1];
for(int i = n-1;i >= 0;i--) sa[--c[x[i]]] = i;
for(int k = 1;k <= n;k <<= 1)
{
int p = 0;
for(int i = n-k;i < n;i++) y[p++] = i;
for(int i = 0;i < n;i++) if(sa[i] >= k) y[p++] = sa[i] - k;
for(int i = 0;i < m;i++) c[i] = 0;
for(int i = 0;i < n;i++) c[x[y[i]]]++;
for(int i = 1;i < m;i++) c[i] += c[i-1];
for(int i = n-1;i >=0;i--) sa[--c[x[y[i]]]] = y[i];
swap(x,y);
p = 1;
x[sa[0]] = 0;
for(int i = 1;i < n;i++)
x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++;
if(p >= n) break;
m = p;
}
cal_height(n-1);
}
int d[MAXN][20];
void rmq_init(int n)
{
for(int i = 1;i <= n;i++)
d[i][0] = height[i];
for(int j = 1;(1<<j) <= n;j++)
for(int i = 1;i+(1<<j) <= n;i++)
d[i][j] = min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int rmq(int a,int b)
{
int k = 0;
while((1<<(k+1)) < (b-a+1)) k++;
return min(d[a][k],d[b-(1<<k)+1][k]);
}
int lcp(int a,int b)
{
a = rank[a],b =rank[b];
if(a > b) swap(a,b);
return rmq(a+1,b);
}
int main()
{
int cas = 0;
while(~scanf("%s",str))
{
if(str[0] == '#') break;
int n = strlen(str);
printf("Case %d: ",++cas);
da(n+1,128);
rmq_init(n);
int ans_time = 0;
vector <int> ans;
for(int len = 1;len <= n;len++)
{
for(int i = 0;i+len < n;i += len)
{
int j = i+len;
int k = lcp(i,j);
int tmp = k/len+1;
int ii = i-(len-k%len);
if(ii >=0 && k%len != 0)
{
if(lcp(ii,ii+len) > k)
tmp++;
}
if(tmp > ans_time)
{
ans_time = tmp;
ans.clear();
ans.push_back(len);
}
else if(tmp == ans_time)
{
ans.push_back(len);
}
}
}
//printf("ti = %d\n",ans_time);
//for(int i = 0;i < ans.size();i++)
//printf("i = %d,ans = %d\n",i,ans[i]);
int ok = 0;
int ans_pos = 0,ans_len = 1;
for(int i = 1;i <= n && !ok;i++)
{
for(int j = 0;j < ans.size();j++)
{
if(sa[i]+ans[j] >= n) break;
if(lcp(sa[i],sa[i]+ans[j]) >= (ans_time-1)*ans[j])
{
ans_pos = sa[i];
ans_len = ans[j]*ans_time;
ok = 1;
break;
}
}
}
for(int i = 0;i < ans_len;i++)
printf("%c",str[ans_pos+i]);
puts("");
}
return 0;
}
/*
bacbacb
*/