HDU_2890
在罗穗骞的论文里有说过至少重复K次的可重叠的最长子串该怎么找,只不过这个题改成了不可重叠。我用的是比较暴力的办法,把按height值分组之后每组内sa[i]的值提取出来排个序,然后扫一遍看能不能形成至少K个不重叠的子串。
此外这个题有两个大坑:①题目中所谓的subsequence应该是substring,在HIT的OJ上这个题目的描述就都是用的substring;②所谓的字典序可能会带来歧义,比如结果有两种可能5 100和5 99,如果将整数当成字符串来处理显然是5 100应该字典序更小,因为100的字典序比99小,但就这个题目而言应该是5 99的字典序比较小,也就是说要把每个整数当成一个字符来看待。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXD 50010 char a[MAXD]; int N, K, q[MAXD], FLAG; struct El { int id, v, r; }el[MAXD]; bool cmp1(const El &x, const El &y) { return x.v < y.v; } bool cmp2(const El &x, const El &y) { return x.id < y.id; } struct Suffix { int r[MAXD], rank[MAXD], sa[MAXD], height[MAXD], ws[MAXD], wv[MAXD], wa[MAXD], wb[MAXD]; int cmp(int *p, int x, int y, int l) { return p[x] == p[y] && p[x + l] == p[y + l]; } void da(int n, int m) { int i, j, p, *x = wa, *y = wb, *t; for(i = 0; i < m; i ++) ws[i] = 0; for(i = 0; i < n; i ++) ++ ws[x[i] = r[i]]; for(i = 1; i < m; i ++) ws[i] += ws[i - 1]; for(i = n - 1; i >= 0; i --) sa[-- ws[x[i]]] = i; for(j = 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 ++) ws[i] = 0; for(i = 0; i < n; i ++) ++ ws[wv[i]]; for(i = 1; i < m; i ++) ws[i] += ws[i - 1]; for(i = n - 1; i >= 0; i --) sa[-- ws[wv[i]]] = y[i]; for(t = x, x = y, y = t, x[sa[0]] = 0, i = p = 1; i < n; i ++) x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p ++; } } void calheight(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 ++); } void init() { int i, cnt; for(i = 0; i < N; i ++) { scanf("%d", &el[i].v); el[i].id = i; } std::sort(el, el + N, cmp1); el[0].r = cnt = 1; for(i = 1; i < N; i ++) el[i].r = el[i].v == el[i - 1].v ? cnt : ++ cnt; std::sort(el, el + N, cmp2); for(i = 0; i < N; i ++) r[i] = el[i].r; r[N] = 0; da(N + 1, N + 1); calheight(N); } int check(int k, int rear) { int i, pre, cnt; std::sort(q, q + rear); pre = q[0], cnt = 1; for(i = 1; i < rear; i ++) if(q[i] - pre >= k) ++ cnt, pre = q[i]; return cnt >= K; } int deal(int k) { int i, j, rear = 0; for(i = 1; i <= N; i ++) { if(height[i] < k) { if(check(k, rear)) { FLAG = sa[i - 1]; return 1; } q[0] = sa[i], rear = 1; } else q[rear ++] = sa[i]; } if(check(k, rear)) { FLAG = sa[i - 1]; return 1; } return 0; } void solve() { int i, j, min = 1, mid, max = N / 2 + 1; init(); for(;;) { mid = min + max >> 1; if(min == mid) break; if(deal(mid)) min = mid; else max = mid; } deal(mid); printf("%d\n", mid); for(i = FLAG, j = 0; j < mid; i ++, j ++) printf("%d\n", el[i].v); } }suffix; void solve() { scanf("%d%d", &N, &K); suffix.solve(); } int main() { int t; scanf("%d", &t); while(t --) { solve(); if(t) printf("\n"); } return 0; }