[bzoj1717][Milk Patterns 产奶的模式]

题目链接

思路

先求出后缀数组,并且求出LCP。二分一下长度len。check的时候就是看有没有连续的k个后缀的LCP大于len。也就是判断是不是有连续的k-1个height大于len。

代码

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 20000+10;
ll read() {
   ll x = 0,f = 1;char c = getchar();
   while(c < '0' || c > '9') {
      if(c == '-') f = -1;c = getchar();
   }
   while(c >= '0' && c <= '9') {
      x = x * 10 + c - '0';
      c = getchar();
   }
   return x * f;
}
int s[N],sa[N],height[N],rk[N],c[N * 100],x[N],y[N];
int n,m,K,h[N];
void get_sa() {
   for(int i = 1;i <= n;++i) ++c[x[i] = s[i]];
   for(int i = 2;i <= m;++i) c[i] += c[i - 1];
   for(int i = n;i >= 1;--i) sa[c[x[i]]--] = i;
   for(int k = 1;k <= n;k <<= 1) {
      int num = 0;
      for(int i = n - k + 1;i <= n;++i) y[++num] = i;
      for(int i = 1;i <= n;++i) if(sa[i] > k) y[++num] = sa[i] - k;
      for(int i = 1;i <= m;++i) c[i] = 0;
      for(int i = 1;i <= n;++i) ++c[x[i]];
      for(int i = 2;i <= m;++i) c[i] += c[i - 1];
      for(int i = n;i >= 1;--i) {
         sa[c[x[y[i]]]--] = y[i];
         y[i] = 0;
      }

      swap(x,y);
      num = 1;
      x[sa[1]] = 1;
      for(int i = 2;i <= n;++i) {
         x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
      }
      if(num >= n) break;
      m = num;
   }
}
void get_height() {
   for(int i = 1;i <= n;++i) rk[sa[i]] = i;
   int k = 0;
   for(int i = 1;i <= n;++i) {
      if(rk[i] == 1) continue;
      if(k) --k;
      int j = sa[rk[i] - 1];
      while(s[i + k] == s[j + k] && j + k <= n && i + k <= n) ++k;
      height[rk[i]] = h[i] = k;
   }
}
int check(int x) {
   int now = 0;
   for(int i = 1;i <= n;++i) {
      if(height[i] >= x) {
         now ++;
         if(now >= K - 1) return 1;
      }
      else now = 0;
   }
   return 0;
}
void erfen() {
   int l = 1,r = n,ans = 0;
   while(l <= r) {
      int mid = (l + r) >> 1;
      if(check(mid)) ans = mid,l = mid + 1;
      else r = mid - 1;
   }
   cout<<ans;
}
int main() {
   n = read();K = read();
   for(int i = 1;i <= n;++i) s[i] = read(),m = max(m,s[i]);
   get_sa();
   get_height();
   erfen();
   return 0;
}

一言

就算你诚实,可生活一样在欺骗你。

posted @ 2018-12-19 22:23  wxyww  阅读(251)  评论(0编辑  收藏  举报