码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-07-03 00:43:37      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:using   ref   content   答案   一个   amp   opera   区间   fir   

题目传送门

  传送门

  写了一个平方暴力草榜了

  考虑找出所有本原平方串,然后计算直接每个 +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;
}

  

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

标签:using   ref   content   答案   一个   amp   opera   区间   fir   

原文地址:https://www.cnblogs.com/yyf0309/p/13227804.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!