【做题】BZOJ2534 L-gap字符串——调和级数

题意:给出一个字符串,问其中有多少个子串恰好为\(uvu\)的形式。其中,\(u\)非空,\(v\)的长度恰好为\(l\)

\(n \leq 5 \times 10^4\)

我们设两个后缀的起点分别为\(a,b \, (a < b)​\),那么,它们能贡献一个合法的子串当且仅当\(lcp(a,b) + l \geq b - a​\)。这样,我们得到了\(O(n^2)​\)的暴力。

由于\(lcp(a,b)\)\(b-a\)没有什么关系,所以我们考虑枚举\(b-a\)。设\(b-a = s\)。那么,答案中\(u\)的长度就要满足\(|u| \geq s - l\)。因此,我们可以忽视长度小于\(s-l\)的字符串。

考虑这样一种做法:枚举\(s-l\),并且把字符串分成\(\left\lceil \frac {n} {s-l} \right\rceil\)段,于是产生\(O \left(\frac {n} {s-l} \right)\)个端点。我们发现,所有满足\(|u| \geq s-l\)的子串\(u\)都至少覆盖一个端点。因此,我们枚举所有端点,并计算所有覆盖它的子串对答案的贡献。为了避免重复计算,我们只在一个子串覆盖的最右边的端点计算它的贡献。

现在,我们已有一个端点\(p\),那么另一个\(u\)的起点就在\(p + s\)。那么,只要求出\(lcp(p,p+s)\)\(lcs(p,p+s)\),我们就能得出所有以\(p\)为其覆盖的最后一个端点的可能的\(u\)的数量。

因为\(H_n = \ln n + O(1)\),所以如果使用\(O(1)\)的lcs和lcp,时间复杂度是\(O(n \log n)\)的。(但博主写了\(O(n \log^2 n)\)

#include <bits/stdc++.h>
using namespace std;
const int N = 80010, BAS = 233;
typedef unsigned long long ull;
ull has[N],mul[N];
long long ans;
int n,l;
char s[N];
ull gethas(int a,int b) {
  return has[b] - has[a-1] * mul[b-a+1];
}
bool check(int a,int b,int c,int d) {
  return gethas(a,b) == gethas(c,d);
}
int lcs(int a,int b) {
  int l = 0, r = min(a,b), ret = 0, mid;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (check(a-mid+1,a,b-mid+1,b)) l = mid + 1, ret = mid;
    else r = mid - 1;
  }
  return ret;
}
int lcp(int a,int b) {
  int l = 0, r = min(n - a + 1, n - b + 1), ret = 0, mid;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (check(a,a+mid-1,b,b+mid-1)) l = mid + 1, ret = mid;
    else r = mid - 1;
  }
  return ret;
}
int main() {
  scanf("%d",&l);
  scanf("%s",s+1);
  n = strlen(s+1);
  for (int i = 1 ; i <= n ; ++ i)
    has[i] = has[i-1] * BAS + s[i];
  mul[0] = 1;
  for (int i = 1 ; i <= n ; ++ i)
    mul[i] = mul[i-1] * BAS;
  for (int s = 1 ; s <= n ; ++ s) {
    for (int i = 1, j = 1 + s + l, a, b ; j <= n ; i += s, j += s) {
      a = lcs(i,j);
      b = lcp(i,j);
      if (b > s) continue;
      ans += max(0,a + b - s);
    }
  }
  printf("%lld\n",ans);
  return 0;
}

小结:一些基本套路都不会……字符串能力有待提高。

posted @ 2018-07-31 14:54  莫名其妙的aaa  阅读(180)  评论(0编辑  收藏  举报