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

題目傳送門

  傳送門

  寫了一個平方暴力草榜了

  考慮找出所有本原平方串,然後計算直接每個 +1 然後減去相鄰的,做一個掃描線。你在想 peach

  很顯然,沒有算到非本原平方串。考慮每個非本原平方串是恰好一個本原平方串重複若干次。

  考慮兩個不同本原串分別重複若干次是一定不相同的,否則可以找到一個更小的週期。

  因此計算答案可以考慮計算每種平方串在區間內最大能連續重複的次數的和。

  注意到當詢問區間包含一個 runs 或者包含 runs 的一個前綴或者後綴的時候易於計算答案。這時候只用考慮 $O(n\log n)$ 個串在區間中出現了多少個本質不同的。

  注意到可能有答案的包含一個點的 runs 數量等於從它開始的本原平方串的數量,因此我們可以暴力枚舉包含詢問區間的 runs 計算算漏的答案。這個計算過程大概可以大力討論 8 種情況然後計算。因爲太懶了,直接把這部分換成 $O(period)$ 暴力。

  理論上可以做到 $O(n\log^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 << '\n';
    } 

    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 << '\n';
        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\n", ans[i]);
  }
  return 0;
}

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章