Skip to content

Commit dc8d881

Browse files
committed
update
1 parent a095a03 commit dc8d881

27 files changed

Lines changed: 894 additions & 57 deletions

‎algorithm/mo.hpp‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
struct Mo {
4+
using F = function<void(int)>;
5+
int n;
6+
vector<int> left, right;
7+
Mo(int size) : n(size) {}
8+
void add_query(int l, int r) { // [l,r)
9+
left.emplace_back(l);
10+
right.emplace_back(r);
11+
}
12+
void run(const F& add_left, const F& add_right, const F& del_left, const F& del_right, const F& query) {
13+
const int q = left.size();
14+
if (q == 0) return;
15+
const int width = max(1, (int)(n / sqrt(q)));
16+
vector<int> order(q);
17+
iota(order.begin(), order.end(), 0);
18+
sort(order.begin(), order.end(), [&](int i, int j) {
19+
if (left[i] / width != left[j] / width) return left[i] < left[j];
20+
return right[i] < right[j];
21+
});
22+
int l = 0, r = 0;
23+
for (int i : order) {
24+
while (l > left[i]) add_left(--l);
25+
while (r < right[i]) add_right(r++);
26+
while (l < left[i]) del_left(l++);
27+
while (r > right[i]) del_right(--r);
28+
query(i);
29+
}
30+
}
31+
void run(const F& add, const F& del, const F& query) {
32+
run(add, add, del, del, query);
33+
}
34+
};

‎data-structure/sparse-table.hpp‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ struct SparseTable {
2626
{
2727
assert(0 <= l && l < r && r <= n);
2828
int j = 0;
29-
while ((1 << j) <= r - l) j++;
30-
j--;
29+
while ((2 << j) <= r - l) j++;
3130
return op(st[j][l], st[j][r - (1 << j)]);
3231
}
3332
};

‎docs/math/min-of-mod-of-linear.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
整数 $M,A,B$ に対し $f(x)=(Ax+B)\bmod M$ とする.
2+
3+
任意の $0\leq y\lt x$ に対して $f(y)\lt f(x)$ となる $x$ 全体の集合を $S$ とすると,$S$ は $O(\log M)$ 個の
4+
5+
整数 $N,M,A,B$ に対し $\min\{f(x) \mid 0 \leq x \lt N\}$ を求めることも $O(\log M)$ 時間でできる.
6+
7+
- min を求める問題はモノイド版 floor sum でも解ける.
8+
9+
関連記事
10+
11+
- Library Checker:[https://judge.yosupo.jp/problem/min_of_mod_of_linear]
12+
- 解説記事:[https://maspypy.com/library-checker-min-of-mod-of-linear]
13+
14+
## アルゴリズム
15+

‎docs/number-theory/lucy-dp.md‎

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
正整数 $N$ が与えられたとき,完全乗法的関数で prefix の和が簡単に計算できる $f$ について $\sum_{p:\text{prime},p\leq N}f(p)$ を $O(N^{2/3}/(\log N)^{1/3})$ 時間で求められる.
2+
3+
以下の情報を与える必要がある.
4+
- 正整数 $k$ に対する $\sum_{i=1}^{\lfloor N/k\rfloor}f(i)$ の値($O(\sqrt{N})$ 個).
5+
- $\sqrt{N}$ 以下の素数に対する $f$ の値.
6+
- 実際は上の総和から計算できる.
7+
8+
9+
例題:
10+
- https://atcoder.jp/contests/jsc2024-final/tasks/jsc2024_final_b
11+
12+
13+
$f$ の例:
14+
- $f(n)=n^k$:$k=0$ のとき $\sum_{p:\text{prime}}f(p)$ は $N$ 以下の素数の個数である.
15+
- Dirichlet 指標:$4$ で割ったあまりが $1$ の素数の和なども求められる.
16+
17+
## アルゴリズム:$O(N^{3/4}/\log N)$
18+
19+
この節は [1] を大幅に参考にしている.
20+
21+
$S(n)=\sum_{p:\text{prime},p\leq n}f(p)$ とおく.
22+
23+
エラトステネスの篩の要領で計算する.
24+
25+
$S_x(n)$ を $\sum_{i=2}^{n}f(i)$ から $x$ 以下の素因数をもつ合成数についての $f$ の値を減じたものとする.$S_x$ は $x$ 以下の数について篩った時点での累積和であり,$x\geq\lfloor\sqrt{n}\rfloor$ ならば $S(n)=S_x(n)$ である.
26+
また $S_1(n)=\sum_{i=2}^{n}f(i)$ である.
27+
28+
以下最小素因数を $\operatorname{lpf}(n)$ で表すことにする.
29+
30+
$S_x$ を $S_{x-1}$ で表す.
31+
$x$ が素数でないならば篩うことはなく $S_x=S_{x-1}$ である.
32+
$x$ が素数であるとき,エラトステネスの篩では $\operatorname{lpf}(i)=x$ かつ $i\neq x$ なる $i$ が篩われる.特に $x^2$ 未満の数は篩われないため以下が成り立つ.
33+
$$S_x(n)=\begin{cases}
34+
S_{x-1}(n)-\left(S_{x-1}(\lfloor n/x \rfloor)-S_{x-1}(x-1)\right)f(x)&(x:\text{prime}, x^2\leq n)\\
35+
S_{x-1}(n)&(\text{otherwise})
36+
\end{cases}$$
37+
38+
$S(N)$ を求めるためには $S_x(\lfloor N/*\rfloor)$ の形の部分だけ管理すればよく,$n$ について降順に計算することで in-place に更新できる.
39+
$\lfloor N/*\rfloor$ のとりうる値の種類数は $O(\sqrt{N})$ であるため空間計算量は $O(\sqrt{N})$ になる.
40+
41+
時間計算量は $\lfloor N/*\rfloor$ の取り得る値すべてについての,その平方根以下の素数の個数の総和のオーダーである.
42+
素数定理
43+
$$\pi(n)\approx\operatorname{Li}(n),\quad \operatorname{Li}(x)=\int_{2}^{x}\frac{1}{\log t}dt\approx\frac{x}{\log x}$$
44+
を用いれば次のように見積もれる.
45+
46+
$$\begin{align*}
47+
\sum_{n=2}^{\lfloor\sqrt{N}\rfloor}\pi(\sqrt{n})
48+
+\sum_{n=1}^{\lfloor\sqrt{N}\rfloor}\pi\left(\sqrt{\frac{N}{n}}\right)
49+
%&\approx\int_{2}^{\sqrt{N}}\operatorname{Li}(\sqrt{x})dx+\int_{1}^{\sqrt{N}}\operatorname{Li}\left(\sqrt{N/x}\right)dx\\
50+
&\approx\int_{2}^{\sqrt{N}}\frac{\sqrt{x}}{\log\sqrt{x}}dx+\int_{1}^{\sqrt{N}}\frac{\sqrt{N/x}}{\log\sqrt{N/x}}dx\\
51+
&\leq\int_{2}^{\sqrt{N}}\frac{N^{1/4}}{\frac{1}{2}\log x}dx+\int_{1}^{\sqrt{N}}\frac{\sqrt{N/x}}{\log N^{1/4}}dx\\
52+
&\approx N^{1/4}\cdot 2\operatorname{Li}(\sqrt{N})+\frac{1}{\log N^{1/4}}\cdot\frac{N^{3/4}}{2}\\
53+
&=O\left(\frac{N^{3/4}}{\log N}\right)
54+
\end{align*}$$
55+
56+
57+
以上の内容をアルゴリズムの形でまとめておく.
58+
$Q=\{\lfloor N/i\rfloor \mid 1\leq i\leq N\}$ とする.
59+
60+
> - $S[q]=\sum_{i=2}^{q}f(i)$ と初期化.
61+
> - $p^2\leq N$ なる素数 $p$ に対して以下を行う.
62+
> - $p^2\leq q$ なる $q\in Q$ について降順に $S[q]$ を $S[q]-(S[\lfloor q/p\rfloor]-S[p-1])f(p)$ で更新する.
63+
> - return $S$.
64+
65+
## 高速化:$\tilde O(N^{2/3})$
66+
67+
$\tilde O(N^{2/3})$ 時間に高速化できる.
68+
69+
[2] では $O(N^{2/3}(\log N)^{1/3})$ 時間 / $\tilde O(N^{2/3})$ 空間のアルゴリズムが紹介されている.そこまで大きな改善ではなく空間計算量は悪化しているが実装はシンプルである.
70+
71+
<!--
72+
Fenwick Tree による高速化ができる.
73+
74+
$\sqrt{N}\lt M\leq N$ なる $M$ をとり,$1,2,\dots,M$ については実際にエラトステネスの篩を行いながら,そこの分の $S$ の値を index が $1,\dots,M$ の Fenwick Tree を用いて管理する.
75+
76+
> - $S[q]=\sum_{i=2}^{q}f(i)$ と初期化.
77+
> - Fenwick Tree $F$ を index $1,\dots,M$ について初期化.$i\geq 2$ について $F[i]=f(i)$ とする.
78+
> - boolean 配列 $\mathrm{sieve}$ を index $2,3,\dots,M$ について $\mathrm{false}$ で初期化.
79+
> - $p=2,3,\dots,\lfloor\sqrt{N}\rfloor$ に対して順に以下を行う.
80+
> - $\mathrm{sieve}[p]=\mathrm{true}$ ならば continue.
81+
> - $p^2\leq q$ かつ $q\gt M$ なる $q\in Q$ について降順に $S[q]$ を $S[q]-(S'(\lfloor q/p\rfloor)-S'(p-1)-1)f(p)$ で更新する.ここで $S'(i)$ は $i>M$ ならば $S[i]$,そうでないならば $F$ における $1$ から $i$ までの和.
82+
> - $\mathrm{sieve}$ をエラトステネスの篩の要領で $p$ について更新し,$F$ も合わせて更新する.
83+
> - return $S$.
84+
85+
計算量を評価.
86+
87+
$F$ の更新回数は高々 $M$ 回なので $O(M\log M)$ 時間.
88+
89+
$S$ の直接的な更新は $q>M$ なる $q\in Q$ についてのみであるから,その回数は前節と同様にして
90+
$$\begin{align*}
91+
\sum_{n=1}^{\lfloor N/M\rfloor}\pi\left(\sqrt{\frac{N}{n}}\right)
92+
&\approx\int_{1}^{N/M}\operatorname{Li}\left(\sqrt{N/x}\right)dx\\
93+
&\leq \int_{1}^{N/M}\int_2^{\sqrt{N/x}}\frac{1}{\log t} dt dx\\
94+
&\leq \int_2^{\sqrt{N}}\int_{1}^{\min(N/M,N/t^2)}\frac{1}{\log t} dx dt\\
95+
&= \int_2^{\sqrt{M}}\frac{N/M}{\log t} dt+\int_{\sqrt{M}}^{\sqrt{N}}\frac{N/t^2}{\log t} dt\\
96+
&=O\left(\frac{N}{\sqrt{M}\log M}\right)
97+
\end{align*}$$
98+
と評価できる.
99+
100+
更新において Fenwick Tree の総和取得を行うので,全体の計算量は $O\left(M\log M+N/\sqrt{M}\right)$ 時間であり,$M\approx(N/\log N)^{2/3}$ で $O(N^{2/3}(\log N)^{1/3})$ 時間となる.
101+
-->
102+
103+
104+
### $O(N^{2/3}/(\log N)^{1/3})$ 時間
105+
106+
[1] の内容.
107+
108+
計算量を評価しなおす.素数 $p$ の計算量への寄与は
109+
$$\max(\sqrt{N}-p^2,0)+\min(N/p^2,\sqrt{N})$$
110+
であるので,時間計算量は
111+
$$\int_{2}^{\sqrt{N}}\left(\max(\sqrt{N}-x^2,0)+\min(N/x^2,\sqrt{N})\right)\frac{1}{\log x} dx$$
112+
と近似できる.ここで $\frac{1}{\log x}$ は $\frac{d\operatorname{Li}(x)}{dx}=\frac{1}{\log x}$ に由来する.
113+
114+
$p\leq N^{1/6}$ なる $p$ に対応する部分は以下のように評価できる.
115+
$$\begin{align*}
116+
&\int_{2}^{N^{1/6}}\left(\max(\sqrt{N}-x^2,0)+\min(N/x^2,\sqrt{N})\right)\frac{1}{\log x}dx\\
117+
&=\int_{2}^{N^{1/6}}\left((\sqrt{N}-x^2)+\sqrt{N}\right)\frac{1}{\log x}dx\\
118+
&\leq 2\sqrt{N}\operatorname{Li}(N^{1/6})\\
119+
&=O\left(\frac{N^{2/3}}{\log N}\right)
120+
\end{align*}$$
121+
122+
また $N^{1/3}\leq p\leq N^{1/2}$ なる $p$ に対応する部分は以下のように評価できる.
123+
$$\begin{align*}
124+
&\int_{N^{1/3}}^{N^{1/2}}\left(\max(\sqrt{N}-x^2,0)+\min(N/x^2,\sqrt{N})\right)\frac{1}{\log x}dx\\
125+
&=\int_{N^{1/3}}^{N^{1/2}}\frac{N}{x^2}\cdot\frac{1}{\log x}dx\\
126+
&\leq\int_{N^{1/3}}^{N^{1/2}}\frac{N}{x^2}\cdot\frac{1}{\log N^{1/3}}dx\\
127+
&=O\left(\frac{N^{2/3}}{\log N}\right)\\
128+
\end{align*}$$
129+
130+
従ってこれらの範囲の $p$ については普通に Lucy DP の計算をしても $O\left(\frac{N^{2/3}}{\log N}\right)$ 時間で計算できる.
131+
132+
$N^{1/6}\lt p\lt N^{1/3}$ なる $p$ について考える.
133+
$q\geq N^{2/3}$ なる $q\in Q$ は $O(N^{1/3})$ 個なのでその遷移は愚直に行うことにして,$N^{1/3}\lt p^2\leq q\lt N^{2/3}$ なる $q$ についての遷移を再考する.
134+
135+
(TODO: やる)
136+
137+
> - $S[q]=\sum_{i=2}^{q}f(i)$ と初期化.
138+
> - $p^2\leq N$ なる素数 $p$ に対して以下を行う.
139+
> - $p^2\leq q$ なる $q\in Q$ について降順に $S[q]$ を $S[q]-(S[\lfloor q/p\rfloor]-S[p-1]-1)f(p)$ で更新する.
140+
> - return $S$.
141+
142+
143+
144+
145+
## 参考資料
146+
147+
- [1] : https://rsk0315.github.io/slides/prime-counting.pdf
148+
- [2] : https://gbroxey.github.io/blog/2023/04/09/lucy-fenwick.html

‎docs/tree/distance.md‎

Whitespace-only changes.

‎docs/tree/lca-auxiliary-tree.md‎

Whitespace-only changes.

‎docs/tree/lowest-common-ancestor.md‎

Whitespace-only changes.

‎docs/tree/tree-diameter.md‎

Whitespace-only changes.

‎fps/sum-of-rationals.hpp‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
#include "fps/formal-power-series.hpp"
33
#include "fps/fps-rational.hpp"
44

5+
template <class fps>
6+
pair<fps, fps> SumOfRationals(vector<pair<fps, fps>> rs) {
7+
if (rs.empty()) return {};
8+
for (int i = rs.size() - 1; i > 0; i--) {
9+
int j = i - (i & -i);
10+
rs[j] = {rs[j].first * rs[i].second + rs[i].first * rs[j].second, rs[i].second * rs[j].second};
11+
rs[j].first.shrink();
12+
}
13+
return rs[0];
14+
}
15+
516
template <class mint>
617
FPSRational<mint> SumOfRationals(vector<FPSRational<mint>> rs) {
718
if (rs.empty()) return {};

‎heuristic/time-keeper.hpp‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ class TimeKeeper {
77

88
public:
99
TimeKeeper(int time_threshold) : start_time_(chrono::high_resolution_clock::now()), time_threshold_(time_threshold) {}
10-
bool is_time_over() const {
10+
long long elapsed_ms() const {
1111
auto diff = chrono::high_resolution_clock::now() - this->start_time_;
12-
return chrono::duration_cast<chrono::milliseconds>(diff).count() >= time_threshold_;
12+
return chrono::duration_cast<chrono::milliseconds>(diff).count();
13+
}
14+
double elapsed_ratio() const {
15+
return (double)elapsed_ms() / time_threshold_;
16+
}
17+
bool is_time_over() const {
18+
return elapsed_ms() >= time_threshold_;
1319
}
1420
};

0 commit comments

Comments
 (0)