后缀自动机 (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;
}
}