题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3971
二分答案mid,用height数组判断出现连续k次,记录出现的最大下标1,二分循环时,更新最大下标2,最后输出答案。
View Code
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 40000+100; int us[N], ua[N], ub[N], sa[N]; 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 n, int m){ int i, j, p, *x=ua, *y=ub, *t; for (i=0; i<m; i++) us[i]=0; for (i=0; i<n; i++) us[x[i]=r[i]]++; for (i=1; i<m; i++) us[i]+=us[i-1]; for (i=n-1; i>=0; i--) sa[--us[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<m; i++) us[i]=0; for (i=0; i<n; i++) us[x[i]]++; for (i=1; i<m; i++) us[i]+=us[i-1]; for (i=n-1; i>=0; i--) sa[--us[x[y[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++; } } int rank[N], height[N], arr[N]; void calheight(int *r, 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++); } char str[N]; int main(){ //freopen("D:/a.txt", "r", stdin); int k, n, st, ed, mid, ans, p; while (~scanf("%d", &k) && k){ n = 0; scanf("%s", str); if (k==1){printf("%d 0\n", strlen(str)); continue;} for (int i=0; str[i]; i++) arr[n++] = str[i]; arr[n] = 0; da(arr, n+1, 128); calheight(arr, n); ans = 0, p = -1, st = 0,ed = n; while (st <= ed){ int tp = 0, flag = 0, maxi = 0; mid = st + (ed - st) / 2; for (int i=1,cnt=1; i<=n; i++){ if (height[i]>=mid) cnt++,tp = max(tp,sa[i]); else cnt=1, tp=sa[i]; if (cnt >= k){ flag = 1; maxi = max(maxi, tp); } } if (flag) ans= mid, st = mid+1, p=maxi; else ed = mid-1; } if (ans>0)printf("%d %d\n", ans, p); else puts("none"); } return 0; }