我的模板库

后缀自动机 (SAM)

struct sam {
  int tr[N][26], len[N], fa[N], tot;
  void clear() {
    rep (i, 1, tot) memset(tr[i], 0, sizeof tr[i]), len[i] = fa[i] = 0;
    tot = 1;
  }
  int insert(int p, int c) {
    int cur = ++ tot;
    len[cur] = len[p] + 1;
    while (p && tr[p][c] == 0) {
      tr[p][c] = cur, p = fa[p];
    }
    if (p == 0) fa[cur] = 1;
    else {
      int q = tr[p][c];
      if (len[q] == len[p] + 1) {
        fa[cur] = q;
      } else {
        int r = ++ tot;
        len[r] = len[p] + 1, fa[r] = fa[q];
        memcpy(tr[r], tr[q], sizeof tr[r]);
        fa[cur] = fa[q] = r;
        while (tr[p][c] == q) {
          tr[p][c] = r, p = fa[p];
        }
      }
    }
    return cur;
  }
} sam;

ex-BSGS

const int N = 2e5 + 5, mod = 998244353, inf = 1e9;

int power(int x, int y, int m = mod) {
	int ans = 1;
	for (; y; y >>= 1, x = 1LL * x * x % m)
		if (y & 1) ans = 1LL * ans * x % m;
	return ans;
}

__gnu_pbds::gp_hash_table<int, int> hdq; 

int phi(int x) {
	int ans = x;
	for (int i = 2; i <= x / i; i ++)
		if (x % i == 0) {
			ans = ans / i * (i - 1);
			while (x % i == 0) x /= i;
		}
	if (x > 1) ans = ans / x * (x - 1);
	return ans;
}

int exBSGS(int a, int b, int m) {
// 求解最小的非负整数 x 使得 a^x === b (mod m)
	static int pp[N], pq[N];
	hdq.clear(), a %= m, b %= m;
    if (m == 1) return 0;
	if (a == 0) {
        if (b == 1) return 0;
        if (b == 0) return 1;
        return -1;
    }
	int t = ceil(sqrt(2 * phi(m)));
	pp[0] = pq[0] = 1;
	rep (i, 1, t) pp[i] = 1LL * pp[i-1] * a % m;
    rep (i, 0, t) if (pp[i] == b) return i;
	rep (i, 1, t) pq[i] = 1LL * pq[i-1] * pp[t] % m;
	rrp (i, t, 1) {
		int s = 1LL * b * pp[i] % m;
        int &p = hdq[s];
        if (p == 0) p = i * (t + 1);
        else if (p % (t + 1) == 0) p += i;
	}
	auto pw = [&](int c) {
		return 1LL * pq[c / t] * pp[c % t] % m;
	};
	int res = inf;
	rep (i, 1, t) {
		int _ = hdq[pq[i]], p = _ / (t + 1), q = _ % (t + 1);
		if (p && pw(i * t - p) == b) res = min(res, i * t - p);
		if (q && pw(i * t - q) == b) res = min(res, i * t - q);
	}
	return res == inf ? -1 : res;
}

min25 筛法

const int N = 2e5 + 5, mod = 1e9 + 7;
const int i6 = (mod + 1) / 6;

int pr[N], m;

void seive(int n) {
  static bitset<N> vis;
  m = 0; 
  rep (i, 2, n) {
    if (vis.test(i)) continue;
    pr[++ m] = i;
    rep (j, i, n / i) vis.set(i * j);
  }
  // cerr << m << '\n';
}

int get(LL x) { return x %= mod, x * (x - 1) % mod; }
int sum2(LL n) { return n %= mod, (n + 1) * n % mod * (2 * n + 1) % mod * i6 % mod; }
int sum1(LL n) { return n %= mod, n * (n + 1) / 2 % mod; }

LL n;
int t, cnt, sp[N], id1[N], id2[N];
int g1[N], g2[N], h[N];
LL val[N];

int Id (LL x) { return x > t ? id2[n / x] : id1[x]; }
int H (LL x) { return h[Id(x)]; }

int S (LL n, int j) {
  if (pr[j] >= n) return 0;
  int ans = (mod + H(n) - h[id1[pr[j]]]) % mod;
  rep (k, j + 1, m) {
    if (pr[k] > n / pr[k]) break;
    for (LL x = pr[k]; x <= n; x *= pr[k])
      ans = (ans + 1LL * get(x) * (S(n / x, k) + (x > pr[k]))) % mod;
  }
  return ans;
}

void fakemain() {
  cin >> n, seive(t = sqrt(n));
  rep (i, 1, t) {
    val[++ cnt] = i, id1[i] = cnt;
    val[++ cnt] = n / i, id2[i] = cnt;
  }
  rep (i, 1, cnt) g1[i] = sum2(val[i]) - 1, g2[i] = sum1(val[i]) - 1;
  vector<int> id(cnt, 0);
  iota(id.begin(), id.end(), 1);
  sort(id.begin(), id.end(), [&](int x, int y) { return val[x] > val[y]; });
  rep (j, 1, m) sp[j] = 1LL * pr[j] * pr[j] % mod;
  rep (j, 1, m) {
    for (auto i : id) {
      LL n = val[i];
      if (pr[j] > n / pr[j]) break;
      int k = Id(n / pr[j]), q = id1[pr[j-1]];
      g1[i] = (g1[i] - 1LL * sp[j] * (g1[k] - g1[q])) % mod;
      g2[i] = (g2[i] - 1LL * pr[j] * (g2[k] - g2[q])) % mod;
      g1[i] += (g1[i] < 0) * mod, g2[i] += (g2[i] < 0) * mod;
    }
  }
  rep (i, 1, cnt) h[i] = (g1[i] + mod - g2[i]) % mod;
  cout << (S(n, 0) + 1) % mod;
}

集合幂级数全家桶

int cnt[N], hb[N], inv[N];
int get_inv(int x) {
  int ans = 1, y = mod - 2;
  for (; y; x = 1LL * x * x % mod, y >>= 1)
    if (y & 1) ans = 1LL * ans * x % mod;
  return ans;
}
void prework(int n) {
  rep (i, 1, (1 << n) - 1) {
    cnt[i] = cnt[i >> 1] + (i & 1);
    hb[i] = hb[i >> 1] + 1;
    if (i == 1) inv[1] = 1;
    else inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
  }
}

void add(int *f, int *g, int *h, int n) { // h = f + g
  rep (i, 0, (1 << n) - 1) h[i] = pls(f[i], g[i]);
}

void del(int *f, int *g, int *h, int n) { // h = f - g
  rep (i, 0, (1 << n) - 1) h[i] = pls(f[i], mod - g[i]);
}

void mul(int *f, int *g, int *h, int n) { // h = f * g
  static int F[N][22], G[N][22], H[N][22];
  int U = (1 << n) - 1;
  rep (i, 0, U) memset(F[i], 0, sizeof F[i]), F[i][cnt[i]] = f[i];
  rep (i, 0, U) memset(G[i], 0, sizeof G[i]), G[i][cnt[i]] = g[i];
  auto fmt_poly = [&](int F[N][22]) {
    rep (i, 0, n-1) rep (j, 0, U) if (j >> i & 1)
      rep (k, 0, n) inc(F[j][k], F[j ^ (1 << i)][k]);
  };
  fmt_poly(F), fmt_poly(G);
  auto ifmt_poly = [&](int F[N][22]) {
    rep (i, 0, n-1) rep (j, 0, U) if (j >> i & 1)
      rep (k, 0, n) inc(F[j][k], mod - F[j ^ (1 << i)][k]);
  };
  rep (i, 0, U) {
    memset(H[i], 0, sizeof H[i]);
    rep (j, 0, n) rep (k, 0, n - j)
      inc(H[i][j + k], 1LL * F[i][j] * G[i][k] % mod);
  }
  ifmt_poly(H);
  rep (i, 0, U) h[i] = H[i][cnt[i]];
}

void com(int *f, int *g, int *h, int n) { // h = f(g)
  static int F[22][N], G[N], H[N];
  int U = (1 << n) - 1, fac = 1;
  rep (i, 0, n) {
    F[i][0] = 1LL * fac * f[i] % mod;
    fac = 1LL * fac * (i + 1) % mod;
  }
  rep (i, 1, n) {
    rep (s, 0, U) G[s] = (hb[s] == i) * g[s];
    rep (j, 0, n-i) mul(F[j+1], G, H, i), add(F[j], H, F[j], i);
  }
  rep (i, 0, U) h[i] = F[0][i];
}

void exp(int *f, int *F, int n) { // F = exp(f)
  static int G[N], H[N];
  int U = (1 << n) - 1;
  fill(F, F + U, 0), F[0] = 1;
  rep (i, 1, n) {
    rep (s, 0, U) G[s] = (hb[s] == i) * f[s];
    mul(F, G, H, i), add(F, H, F, i);
  }
}

void ln(int *f, int *h, int n) { // h = ln(f)
  static int F[N][22], G[22];
  int U = (1 << n) - 1;
  rep (i, 0, U) F[i][cnt[i]] = f[i];
  auto fmt_poly = [&](int F[N][22]) {
    rep (i, 0, n-1) rep (j, 0, U) if (j >> i & 1)
      rep (k, 0, n) inc(F[j][k], F[j ^ (1 << i)][k]);
  };
  fmt_poly(F);
  rep (i, 0, U) {
    rep (j, 0, n) G[j] = 0;
    rep (j, 1, n) {
      rep (k, 1, j-1) inc(G[j], 1LL * k * G[k] % mod * F[i][j - k] % mod);
      G[j] = (F[i][j] + 1LL * (mod - inv[j]) * G[j]) % mod;
    }
    rep (j, 0, n) F[i][j] = G[j];
  }
  auto ifmt_poly = [&](int F[N][22]) {
    rep (i, 0, n-1) rep (j, 0, U) if (j >> i & 1)
      rep (k, 0, n) inc(F[j][k], mod - F[j ^ (1 << i)][k]);
  };
  ifmt_poly(F);
  rep (i, 0, U) h[i] = F[i][cnt[i]];
}

void Inv(int *f, int *h, int n) { // h * f = 1
  static int F[N][22], G[22];
  int U = (1 << n) - 1;
  rep (i, 0, U) F[i][cnt[i]] = f[i];
  auto fmt_poly = [&](int F[N][22]) {
    rep (i, 0, n-1) rep (j, 0, U) if (j >> i & 1)
      rep (k, 0, n) inc(F[j][k], F[j ^ (1 << i)][k]);
  };
  fmt_poly(F);
  rep (i, 0, U) {
    rep (j, 0, n) G[j] = 0;
    int ii = get_inv(F[i][0]); G[0] = ii;
    assert(1LL * F[i][0] * ii % mod == 1);
    rep (j, 1, n) {
      rep (k, 1, j) inc(G[j], 1LL * G[j - k] * F[i][k] % mod);
      G[j] = 1LL * (mod - ii) * G[j] % mod;
    }
    rep (j, 0, n) F[i][j] = G[j];
  }
  auto ifmt_poly = [&](int F[N][22]) {
    rep (i, 0, n-1) rep (j, 0, U) if (j >> i & 1)
      rep (k, 0, n) inc(F[j][k], mod - F[j ^ (1 << i)][k]);
  };
  ifmt_poly(F);
  rep (i, 0, U) h[i] = F[i][cnt[i]];
}

后缀数组

char s[N];
int rnk[N], sa[N], h[N], n;

inline void SA() {
  static int a[N], tmp[N], b[N] = {0};
  auto work = [&](int p[], int id[]) {
    static int c[N] = {0}, t[N] = {0};
    fill_n(c, n + 1, 0);
    rep (i, 1, n) ++ c[p[i]];
    rep (i, 1, n) c[i] += c[i-1];
    rrp (i, n, 1) t[c[p[id[i]]] --] = id[i];
    rep (i, 1, n) id[i] = t[i];
  };
  rep (i, 1, n) b[s[i]] = 1;
  rep (i, 1, 122) b[i] += b[i-1];
  rep (i, 1, n) rnk[i] = b[s[i]];
  iota(a, a + n + 1, 0);
  for (int L = 1; tmp[a[n]] < n; L <<= 1) {
    rep (i, 1, n) b[i] = (i + L <= n ? rnk[i + L] : 0);
    work(b, a), work(rnk, a);
    for (int i = 1, r = 0; i <= n; ++i)
      tmp[a[i]] = r += (rnk[a[i - 1]] < rnk[a[i]] || b[a[i - 1]] < b[a[i]]);
    memcpy(rnk + 1, tmp + 1, n << 2);
    if (tmp[a[n]] == n) break;
  }
  rep (i, 1, n) sa[rnk[i]] = i;
  int k = 0;
  rep (i, 1, n) if (rnk[i] < n) {
    int j = sa[rnk[i] + 1]; k -= !!k;
    while (s[i + k] == s[j + k]) ++ k;
    h[rnk[i]] = k;
  }
}
posted @ 2025-04-30 19:07  Cynops  阅读(23)  评论(0)    收藏  举报

Loading