P2852 [USACO06DEC]牛奶模式Milk Patterns 后缀数组(poj3261)

简介: P2852 [USACO06DEC]牛奶模式Milk Patterns 后缀数组(poj3261)

题意: 找出现至少k次的子串的最大长度.

思路:据贪心策略,子串变长答案不会减小,所以可以看做是求k个后缀的LCP.因为要求LCP的最大值,而LCP(suffix(sa[i]),suffix(sa[j]))=min{height[k]}(i<j,k∈[i,j]),显然当这k个后缀在排名上连续的时候可以取得最小值.因为若排名不连续,那么涵盖的取最小值的范围一定会变大,而当取值范围变大最小值只会变小.所以这个贪心是正确的.

二分 + 后缀数组(height数组)


我们知道,后缀(j)和后缀(k)的 最 长 公 共 前 缀 为height[rank[j]+1],


height[rank[j]+2],height[rank[j]+3],…,height[rank[k]]中的最小值(设rank[j]<rank[k])。


那么设k个后缀中rank的min=l,max=r,k个的最长公共前缀就是min(height[l+1->r])


所以k个后缀在rank上一定是连续的。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int n, m, k, p;
int s[maxn];
int sa[maxn], rak[maxn], tx[maxn], height[maxn], q[maxn];
struct node {
  int x, y, id;
}a[maxn],b[maxn];
void rsort() {
  for (int i = 1; i <= m; i++) {
    tx[i] = 0;
  }
  for (int i = 1; i <= n; i++) {
    tx[a[i].y]++;
  }
  for (int i = 1; i <= m; i++) {
    tx[i] += tx[i - 1];
  }
  for (int i = 1; i <= n; i++) {
    b[tx[a[i].y]--] = a[i];
  }
  for (int i = 1; i <= m; i++) {
    tx[i] = 0;
  }
  for (int i = 1; i <= n; i++) {
    tx[b[i].x]++;
  }
  for (int i = 1; i <= m; i++) {
    tx[i] += tx[i - 1];
  }
  for (int i = n; i >= 1; i--) {
    a[tx[b[i].x]--] = b[i];
  }
}
void solve() {
  rsort();
  p = 0;
  for (int i = 1; i <= n; i++) {
    if (a[i].x != a[i - 1].x || a[i].y != a[i - 1].y) {
      ++p;
    }
    rak[a[i].id] = p;
  }
  for (int i = 1; i <= n; i++) {
    a[i].x = rak[i];
    a[i].id = sa[rak[i]] = i;
    a[i].y = 0;
  }
  m = p;
}
void ssort() {
  for (int i = 1; i <= n; i++) {
    a[i].x = a[i].y = s[i];
    a[i].id = i;
    m = max(m, s[i]);
  }
  solve();
  for (int j = 1; j <= n; j <<= 1) {
    for (int i = 1; i + j <= n; i++) {
      a[i].y = a[i + j].x;
    }
    solve();
    if (p == n) {
      break;
    }
  }
}
void get_Height() {
  int k = 0;
  for (int i = 1; i <= n; i++) {
    if (k) {
      k--;
    }
    int j = sa[rak[i] - 1];
    while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) {
      k++;
    }
    height[rak[i]] = k;
  }
}
/*
5 2
1 2 1 2 1
*/
int check(int x) {
  int i = 1;
  while (1) {
    for (; i <= n && height[i] < x; i++);
    if (i > n) {
      break;
    }
    int cnt = 1;
    for (; i <= n && height[i] >= x; cnt++, i++);
    if (cnt >= k) {
      return 1;
    }
  }
  return 0;
}
int main() {
  scanf("%d%d", &n, &k);
  for (int i = 1; i <= n; i++) {
    scanf("%d", &s[i]);
  }
  ssort(); get_Height();
  int l = 1, r = n;
  int ans = 0;
  while (l <= r) {
    int mid = (l + r) / 2;
    if (check(mid)) {
      l = mid + 1;
    } else {
      r = mid - 1;
    }
  }
  printf("%d\n", l - 1);
  return 0;
} 
相关文章
hdu 1052 Tian Ji -- The Horse Racing【田忌赛马】(贪心)
hdu 1052 Tian Ji -- The Horse Racing【田忌赛马】(贪心)
52 0
洛谷P2871-[USACO07DEC]Charm Bracelet S(01背包模板题)
洛谷P2871-[USACO07DEC]Charm Bracelet S(01背包模板题)
洛谷P2871-[USACO07DEC]Charm Bracelet S(01背包模板题)
|
移动开发
洛谷P2639-[USACO09OCT]Bessie‘s Weight Problem G(01背包)
洛谷P2639-[USACO09OCT]Bessie‘s Weight Problem G(01背包)
洛谷P2639-[USACO09OCT]Bessie‘s Weight Problem G(01背包)
|
测试技术
HDU-1847,Good Luck in CET-4 Everybody!(巴什博弈)
HDU-1847,Good Luck in CET-4 Everybody!(巴什博弈)
HDU-1009,FatMouse' Trade(贪心水题)
HDU-1009,FatMouse' Trade(贪心水题)
|
Java C语言
HDOJ/HDU 1029 Ignatius and the Princess IV(简单DP,排序)
HDOJ/HDU 1029 Ignatius and the Princess IV(简单DP,排序)
139 0