loj 3311「ZJOI2020」字符串 - 平方串

Posted yyf0309

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj 3311「ZJOI2020」字符串 - 平方串相关的知识,希望对你有一定的参考价值。

题目传送门

  传送门

  写了一个平方暴力草榜了

  考虑找出所有本原平方串,然后计算直接每个 +1 然后减去相邻的,做一个扫描线。你在想 peach

  很显然,没有算到非本原平方串。考虑每个非本原平方串是恰好一个本原平方串重复若干次。

  考虑两个不同本原串分别重复若干次是一定不相同的,否则可以找到一个更小的周期。

  因此计算答案可以考虑计算每种平方串在区间内最大能连续重复的次数的和。

  注意到当询问区间包含一个 runs 或者包含 runs 的一个前缀或者后缀的时候易于计算答案。这时候只用考虑 $O(nlog n)$ 个串在区间中出现了多少个本质不同的。

  注意到可能有答案的包含一个点的 runs 数量等于从它开始的本原平方串的数量,因此我们可以暴力枚举包含询问区间的 runs 计算算漏的答案。这个计算过程大概可以大力讨论 8 种情况然后计算。因为太懒了,直接把这部分换成 $O(period)$ 暴力。

  理论上可以做到 $O(nlog^2 n)$

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

template <typename T>
void pfill(T* pst, const T* ped, T val) {
  for ( ; pst != ped; *(pst++) = val);
}

const int N = 2e5 + 5;
const int bzmax = 19;

typedef class SparseTable {
  public:
    int n;
    int *a;
    int log2[N];
    int f[bzmax][N];

    SparseTable() {	}

    void init(int n, int *a) {
      this->n = n, this->a = a;
      log2[0] = -1;
      for (int i = 1; i <= n; i++) {
        log2[i] = log2[i >> 1] + 1;
      }
      for (int i = 1; i <= n; i++) {
        f[0][i] = a[i];
      }
      for (int i = 1; i < bzmax; i++) {
        for (int j = 1; j + (1 << i) - 1 <= n; j++) {
          f[i][j] = min(f[i - 1][j], f[i - 1][j + (1 << (i - 1))]);
        }
      }
    }

    int query(int l, int r) {
      int b = log2[r - l + 1];
      return min(f[b][l], f[b][r - (1 << b) + 1]);
    }
} SparseTable;

typedef class Pair3 {
  public:
    int x, y, id;

    Pair3() {	}
    Pair3(int x, int y, int id) : x(x), y(y), id(id) {	}
} Pair3;

typedef class SuffixArray {
  public:
    int n;
    char *str;
    int cnt[N];
    SparseTable st;
    Pair3 X[N], Y[N];
    int sa[N], rk[N], hei[N];

    SuffixArray() {	}

    void set(int n, char* str) {
      this->n = n, this->str = str;
    }

    void radix_sort() {
      int m = max(256, n);
      pfill(cnt, cnt + m + 1, 0);
      for (int i = 1; i <= n; i++)
        cnt[X[i].y]++;
      for (int i = 1; i <= m; i++)
        cnt[i] += cnt[i - 1];
      for (int i = 1; i <= n; i++)
        Y[cnt[X[i].y]--] = X[i];

      pfill(cnt, cnt + m + 1, 0);
      for (int i = 1; i <= n; i++)
        cnt[Y[i].x]++;
      for (int i = 1; i <= m; i++)
        cnt[i] += cnt[i - 1];
      for (int i = n; i; i--)
        X[cnt[Y[i].x]--] = Y[i];
    }

    void build() {
      for (int i = 1; i <= n; i++)
        rk[i] = str[i];
      for (int k = 1; k <= n; k <<= 1) {
        for (int i = 1; i + k <= n; i++)
          X[i] = Pair3(rk[i], rk[i + k], i);
        for (int i = n - k + 1; i <= n; i++)
          X[i] = Pair3(rk[i], 0, i);
        radix_sort();
        int dif = 1;
        rk[X[1].id] = 1;
        for (int i = 2; i <= n; i++)
          rk[X[i].id] = (X[i].x == X[i - 1].x && X[i].y == X[i - 1].y) ? (dif) : (++dif);
        if (dif == n) {
          break;
        }
      }
      for (int i = 1; i <= n; i++) {
        sa[rk[i]] = i;
      }
    }

    void get_height() {
      for (int i = 1, j, k = 0; i <= n; i++, k && k--) {
        if (rk[i]) {
          for (j = sa[rk[i] - 1]; i + k <= n && j + k <= n && str[i + k] == str[j + k]; k++);
          hei[rk[i]] = k;
        }
      }
    }

    void init_st() {
      st.init(n, hei);
    }

    int lcp(int u, int v) {
      if (u == v) {
        return n - u + 1;
      }
      u = rk[u], v = rk[v];
      if (u > v) swap(u, v);
      return st.query(u + 1, v);
    }

    int compare(int l1, int r1, int l2, int r2) {
      int len_lcp = lcp(l1, l2);
      int R1 = l1 + len_lcp, R2 = l2 + len_lcp;
      if (R1 > r1 && R2 > r2)
        return ((r1 - l1) > (r2 - l2)) ? (1) : ((r1 - l1 == r2 - l2) ? (0) : (-1));
      if (R1 > r1 || R2 > r2)
        return (R1 > r1) ? (-1) : (1);
      return (str[R1] < str[R2]) ? (-1) : (1);
    }

    int operator [] (int p) {
      return sa[p];
    }
    int operator () (int p) {
      return hei[p];
    }

    void work(int n, char* s) {
      set(n, s);
      build();
      get_height();
      init_st();
    }
} SuffixArray;

typedef class Fenwick {
  public:
    int n;
    vector<int> a;

    void init(int n) {
      this->n = n;
      a.assign(n + 1, 0);
    }
    void add(int idx, int val) {
      for ( ; idx <= n; idx += idx & (-idx))
        a[idx] += val;
    }
    int qry(int idx) {
      int ret = 0;
      for ( ; idx; idx -= (idx & (-idx)))
        ret += a[idx];
      return ret;
    }
} Fenwick;

typedef class Runs {
  public:
    int l, r, d;
    vector<pair<int, int>> range;

    Runs() {  }
    Runs(int l, int r, int d) : l(l), r(r), d(d) { }

    int query(int ql, int qr) {
      ql = max(ql, l);
      qr = min(qr, r + d);
      int ret = 0;
      for (auto rg : range) {
        int rl = rg.first, rr = rg.second;
        if (ql > rl && qr < rr) {
          int cl = rl + (ql - rl + d - 1) / d * d;
          ret += (qr + 1 - cl) / (d << 1);
        }
      }
      return ret;
    }
} Runs;

int n, q;
int ans[N];
vector<Runs> vr;
char s[N], _s[N];
SuffixArray sa, _sa;

typedef class Segment {
  public:
    int l, r;

    Segment() { }
    Segment(int l, int r) : l(l), r(r) {  }

    bool operator < (Segment b) const {
      return sa.compare(l, r, b.l, b.r) == -1;
    }
} Segment;

typedef class Event {
  public:
    int op, x, y, v;

    Event(int op, int x, int y, int v) : op(op), x(x), y(y), v(v) {
      //      cerr << "Event created: " << op << " " << x << " " << y << " " << v << ‘
‘;
    } 

    bool operator < (Event b) const {
      return (x ^ b.x) ? (x > b.x) : (op < b.op);
    }
} Event;

int Less[N];
bool ban[N * 20];
vector<int> cov[N];
map<Segment, int> mpls;
vector<Event> E;

void init_runs() {
  for (int i = 1; i <= n; i++) {
    Less[i + 1] = Less[i] + (n / i);
  }
  for (int d = 1; (d << 1) <= n; d++) {
    int l, r = 0;
    mpls.clear();
    for (int i = d; i + d <= n; i += d) {
      if (i > r) {
        int _i = i + d;
        l = i - _sa.lcp(n - _i + 1, n - i + 1) + 1;
        r = i + sa.lcp(i, _i) - 1;
        if (r - l + 1 < d || ban[Less[d] + i / d]) {
          continue;
        }
        for (int p = d << 1; l + (p << 1) - 1 <= r + d; p = p + d) {
          ban[Less[p] + (l + p - 1) / p] = true;
        }
        for (int j = l; j <= r; j++) {
          cov[j].push_back(vr.size());
        }
        //        cerr << "runs found: " << l << " " << r << " with period " << d << ‘
‘;
        vr.emplace_back(l, r, d);
        int d2 = d << 1;
        for (int j = 0; j < d && l + j + d - 1 <= r; j++) {
          int R = l + j + (r + d - l - j + 1) / d * d;
          vr.back().range.emplace_back(l + j, R - 1);
          for (int t = d2; l + j + t - 1 <= r + d; t += d2) {
            int pl = l + j, pr = R - t;
            E.emplace_back(0, pl, pl + t - 1, 1);
            E.emplace_back(0, pr, pr + t - 1, 1);
            E.emplace_back(0, pl, pr + t - 1, -1);
            Segment s = Segment(pl, pl + t - 1);
            if (mpls.count(s)) {
              int pls = mpls[s];
              E.emplace_back(0, pls, pl + t - 1, -1);
            }
            mpls[s] = pr;
          }
        }
      }
    }
  }
}

int main() {
  scanf("%d%d", &n, &q);
  scanf("%s", s + 1);
  for (int i = 1; i <= n; i++) {
    _s[n - i + 1] = s[i];
  }
  sa.work(n, s);
  _sa.work(n, _s);
  init_runs();
  for (int i = 1, l, r; i <= q; i++) {
    scanf("%d%d", &l, &r);
    E.emplace_back(1, l, r, i);
    for (auto x : cov[l]) {
      ans[i] += vr[x].query(l, r);
    }
  }
  Fenwick fen;
  fen.init(n);
  sort(E.begin(), E.end());
  for (auto e : E) {
    if (!e.op) {
      fen.add(e.y, e.v);
    } else {
      ans[e.v] += fen.qry(e.y);
    }
  }
  for (int i = 1; i <= q; i++) {
    printf("%d
", ans[i]);
  }
  return 0;
}

  

以上是关于loj 3311「ZJOI2020」字符串 - 平方串的主要内容,如果未能解决你的问题,请参考以下文章

@loj - 3043@「ZJOI2019」线段树

loj 2135 「ZJOI2015」幻想乡战略游戏 - 动态点分治

@loj - 2091@ 「ZJOI2016」小星星

[bzoj3926] [loj2137] [Zjoi2015] 诸神眷顾的幻想乡

并不对劲的bzoj3924:loj2135:p3345:[ZJOI2015]幻想乡战略游戏

ZJOI2020训练题2