題意:m表示至少出現m次的字符串,要求最長,並輸出最後一次的子串的位置
height [ i ] 表示 sa [ i ] 與 sa [ i -1 ] 的公共長度
二分最長串的長度
如果找到連續的k-1個 height 大於等於 長度len 即存在長度爲len的串
這時候記錄下最靠右邊的串的位置
(需要特判 m==1 的時候
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <list>
#include <deque>
#include <set>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
typedef long long LL;
const int INF = 1<<29;
const int mod = 2552 ;
const int MAXN = 50010;
int t1[MAXN],t2[MAXN],c[MAXN]; //求SA數組需要的中間變量,不需要賦值
//待排序的字符串放在s數組中,從s[0] 到s[n-1], 長度爲n, 且最大值小於m,
//除s[n-1] 外的所有s[i] 都大於0, r[n-1]=0
//函數結束以後結果放在sa數組中
bool cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int str[], int sa[], int rank[], int height[], int n, int m)
{
n++;
int i, j, p, *x = t1, *y = t2;
//第一輪基數排序,如果s的最大值很大,可改爲快速排序
for(i = 0; i < m; i++)c[i] = 0;
for(i = 0; i < n; i++)c[x[i] = str[i]]++;
for(i = 1; i < m; i++)c[i] += c[i -1];
for(i = n-1; i >= 0; i--)sa[ --c[x[i]]] = i;
for(j = 1; j <= n; j <<= 1)
{
p = 0;
//直接利用sa數組排序第二關鍵字
for(i = n-j; i < n; i++)y[p++] = i; //後面的j 個數第二關鍵字爲空的最小
for(i = 0; i < n; i++) if(sa[i] >= j)y[p++] = sa[i] - j;
//這樣數組y保存的就是按照第二關鍵字排序的結果
//基數排序第一關鍵字
for(i = 0; i < m; i++)c[i] = 0;
for(i = 0; i < n; i++)c[x[y[i]]]++;
for(i = 1; i < m; i++)c[i] += c[i-1];
for(i = n-1; i >= 0; i --)sa[--c[x[y[i]]]] = y[i];
//根據sa和x數組計算新的x數組
swap(x,y);
p = 1;
x[sa[0]] = 0;
for(i = 1; i < n; i++)
x[sa[i]] = cmp(y,sa[i -1],sa[i],j)?p- 1:p++;
if(p >= n) break;
m = p; //下次基數排序的最大值
}
int k = 0;
n--;
for(i = 0; i <= n; i++)rank[sa[i]] = i;
for(i = 0; i < n; i++)
{
if(k)k--;
j = sa[rank[i] -1];
while(str[i+k] == str[j+k])k++;
height[rank[i]] = k;
}
}
int rank[MAXN],height[MAXN];
char str[MAXN];
int r[MAXN];
int sa[MAXN];
int wei;
int gao(int ll,int n,int k)
{
int ans=0;
int now=0;
wei=0;
for(int i=2;i<=n;i++)
{
if(height[i]>=ll)
now++;
else
{
ans=max(ans,now);
if(now+1>=k)
{
for(int j=i-1;now+1;j--,now--)
wei=max(sa[j],wei);
}
now=0;
}
}
ans=max(ans,now);
if(now+1>=k)
{
for(int j=n;now+1;j--,now--)
wei=max(sa[j],wei);
}
if(ans+1>=k)
{
return 1;
}
else return 0;
}
int main()
{
int k;
while(scanf("%d",&k),k)
{
scanf("%s",str);
int len = strlen(str);
if(k==1)
{
printf("%d %d\n",len,0);
continue;
}
int n=len;
for(int i = 0; i < len; i++)
r[i] = str[i];
da(r,sa,rank,height,n,128);
int ll=1,rr=len,ans=0,out=0;
while(ll<=rr)
{
int mm=(ll+rr)>>1;
if(gao(mm,n,k))
{
if(ans<mm)
ans=mm,out=wei;
ll=mm+1;
}
else rr=mm-1;
}
if(ans==0)
printf("none\n");
else
printf("%d %d\n",ans,out);
}
return 0;
}
/*
*/