From c42d7c33b207b5d95dede03682ef1b298b5d1ec0 Mon Sep 17 00:00:00 2001 From: Mikit <37488201+m1kit@users.noreply.github.com> Date: Mon, 21 Sep 2020 23:37:06 +0900 Subject: [PATCH 01/48] Update MaxFlow.java Fix typo --- MaxFlow/MaxFlow.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MaxFlow/MaxFlow.java b/MaxFlow/MaxFlow.java index 61a2548..9aac91c 100644 --- a/MaxFlow/MaxFlow.java +++ b/MaxFlow/MaxFlow.java @@ -187,7 +187,7 @@ public boolean[] minCut(int s) { return reachable; } - private void rangeCheck(int i, int minInlusive, int maxExclusive) { + private void rangeCheck(int i, int minInclusive, int maxExclusive) { if (i < 0 || i >= maxExclusive) { throw new IndexOutOfBoundsException( String.format("Index %d out of bounds for length %d", i, maxExclusive) @@ -195,11 +195,11 @@ private void rangeCheck(int i, int minInlusive, int maxExclusive) { } } - private void nonNegativeCheck(long cap, java.lang.String attribute) { + private void nonNegativeCheck(long cap, String attribute) { if (cap < 0) { throw new IllegalArgumentException( String.format("%s %d is negative.", attribute, cap) ); } } -} \ No newline at end of file +} From 1ef3510db70d149e590422e056041194db91eade Mon Sep 17 00:00:00 2001 From: mikit Date: Tue, 22 Sep 2020 01:03:54 +0900 Subject: [PATCH 02/48] Add Permutation --- Permutation/Permutation.java | 50 ++++++++++++++++++++++++++++++++++++ Permutation/README.md | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 Permutation/Permutation.java create mode 100644 Permutation/README.md diff --git a/Permutation/Permutation.java b/Permutation/Permutation.java new file mode 100644 index 0000000..e46dedb --- /dev/null +++ b/Permutation/Permutation.java @@ -0,0 +1,50 @@ +class Permutation implements java.util.Iterator { + private int[] next; + + public Permutation(int n) { + next = java.util.stream.IntStream.range(0, n).toArray(); + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public int[] next() { + int[] r = next.clone(); + next = nextPermutation(next); + return r; + } + + public static int[] nextPermutation(int[] a) { + if (a == null || a.length < 2) + return null; + int p = 0; + for (int i = a.length - 2; i >= 0; i--) { + if (a[i] >= a[i + 1]) + continue; + p = i; + break; + } + int q = 0; + for (int i = a.length - 1; i > p; i--) { + if (a[i] <= a[p]) + continue; + q = i; + break; + } + if (p == 0 && q == 0) + return null; + int temp = a[p]; + a[p] = a[q]; + a[q] = temp; + int l = p, r = a.length; + while (++l < --r) { + temp = a[l]; + a[l] = a[r]; + a[r] = temp; + } + return a; + } +} diff --git a/Permutation/README.md b/Permutation/README.md new file mode 100644 index 0000000..5aec073 --- /dev/null +++ b/Permutation/README.md @@ -0,0 +1,45 @@ +# クラス Permutation + +本機能は AtCoderLibrary ではなく C++標準ライブラリ `std::next_permutation` の移植です. + +$N$が与えられたとき,長さ$N$の順列を辞書順に列挙することができます. + +## コンストラクタ + +### Permutation + +```java +public Permutation(int n) +``` + +長さ$N$の順列を列挙するイテレータを作ります. 計算量 $O(N)$ + +## メソッド + +### hasNext + +```java +public boolean hasNext() +``` + +イテレータが後続の要素を保持する場合に真を返します.計算量 $O(1)$ + +### next + +```java +public int[] next() +``` + +イテレータの後続の要素を取得します.計算量 $O(N)$ + +### nextPermutation + +```java +public static int[] nextPermutation(int[] a) +``` + +与えられた順列に対して,辞書順でその直後となるような順列を返却します. +但し,入力の配列が辞書順最大の場合は`null`を返却します. +入力配列中の任意の 2 要素が相異なることを仮定しています. +また,入力で与えられた順列を破壊的に変更することに注意してください. +計算量 $O(N)$ From 07528411b37ec6e09ba7e7bc97ae6e4642e59d7c Mon Sep 17 00:00:00 2001 From: mikit Date: Thu, 24 Sep 2020 01:35:52 +0900 Subject: [PATCH 03/48] Implement Iterable for Permutation --- Permutation/Permutation.java | 11 ++++++++++- Permutation/README.md | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Permutation/Permutation.java b/Permutation/Permutation.java index e46dedb..8e85624 100644 --- a/Permutation/Permutation.java +++ b/Permutation/Permutation.java @@ -1,4 +1,8 @@ -class Permutation implements java.util.Iterator { +/* +* Verified +* https://atcoder.jp/contests/abc054/submissions/16977824 +*/ +class Permutation implements java.util.Iterator, Iterable { private int[] next; public Permutation(int n) { @@ -17,6 +21,11 @@ public int[] next() { return r; } + @Override + public java.util.Iterator iterator() { + return this; + } + public static int[] nextPermutation(int[] a) { if (a == null || a.length < 2) return null; diff --git a/Permutation/README.md b/Permutation/README.md index 5aec073..acfe48c 100644 --- a/Permutation/README.md +++ b/Permutation/README.md @@ -4,6 +4,16 @@ $N$が与えられたとき,長さ$N$の順列を辞書順に列挙することができます. +また,拡張 for 文によるイテレーションをサポートしています. +以下のイテレーションは,時間計算量 $O(N * N!)$で動作します. + +``` +Permutation perm = new Permutation(n); +for (int[] p : perm) { + // code here +} +``` + ## コンストラクタ ### Permutation @@ -32,6 +42,14 @@ public int[] next() イテレータの後続の要素を取得します.計算量 $O(N)$ +### iterator + +```java +public Iterator iterator() +``` + +順列を列挙するイテレータを取得します. + ### nextPermutation ```java From 694ffe66a6ca2a9ee466b2b450537a1fa8e0223f Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Fri, 25 Sep 2020 04:14:31 +0900 Subject: [PATCH 04/48] fix bug of MaxFlow --- MaxFlow/MaxFlow.java | 1 + 1 file changed, 1 insertion(+) diff --git a/MaxFlow/MaxFlow.java b/MaxFlow/MaxFlow.java index 61a2548..63dd865 100644 --- a/MaxFlow/MaxFlow.java +++ b/MaxFlow/MaxFlow.java @@ -98,6 +98,7 @@ public long flow(int s, int t, long flowLimit) { long d = dinicDFS(t, s, flowLimit - flow, iter, level); if (d <= 0) break; flow += d; + if (flow == flowLimit) return flow; } } } From 49049aef9c6a4044a83451efd76f5b9d0753ddbd Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Fri, 25 Sep 2020 23:05:35 +0900 Subject: [PATCH 05/48] Test of Lazy Segment Tree --- LazySegTree/.gitignore | 3 + LazySegTree/test/Gen.java | 101 ++++++++ LazySegTree/test/Main.java | 14 ++ LazySegTree/test/NaiveSolution.java | 93 +++++++ LazySegTree/test/Readme.md | 41 +++ LazySegTree/test/Solution.java | 376 ++++++++++++++++++++++++++++ LazySegTree/test/Test.java | 41 +++ 7 files changed, 669 insertions(+) create mode 100644 LazySegTree/.gitignore create mode 100644 LazySegTree/test/Gen.java create mode 100644 LazySegTree/test/Main.java create mode 100644 LazySegTree/test/NaiveSolution.java create mode 100644 LazySegTree/test/Readme.md create mode 100644 LazySegTree/test/Solution.java create mode 100644 LazySegTree/test/Test.java diff --git a/LazySegTree/.gitignore b/LazySegTree/.gitignore new file mode 100644 index 0000000..0a8eadb --- /dev/null +++ b/LazySegTree/.gitignore @@ -0,0 +1,3 @@ +test/answer +test/in +test/out \ No newline at end of file diff --git a/LazySegTree/test/Gen.java b/LazySegTree/test/Gen.java new file mode 100644 index 0000000..174ae8c --- /dev/null +++ b/LazySegTree/test/Gen.java @@ -0,0 +1,101 @@ +package test; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Random; + +public class Gen { + static final int TESTCASE_NUM = 100; + + static final Random rnd = new Random(System.nanoTime()); + + static final int N_MIN = 1; + static final int N_MAX = 5000; + static final int Q_MIN = 1; + static final int Q_MAX = 10000; + static final int A_MIN = -1000000000; + static final int A_MAX = 1000000000; + static final int V_MIN = -1000000000; + static final int V_MAX = 1000000000; + static final int QUERY_MIN = 0; + static final int QUERY_MAX = 7; + + public static void main(String[] args) { + for (int i = 0; i < TESTCASE_NUM; i++) { + String fileName = String.format("LazySegTree/test/in/testcase_%d", i); + try (PrintWriter out = new PrintWriter(new File(fileName))) { + gen(out); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + public static void gen(PrintWriter out) { + final int N = rndIntClosedRange(N_MIN, N_MAX); + final int Q = rndIntClosedRange(Q_MIN, Q_MAX); + final int P_MIN = 0, P_MAX = N - 1; + final int L_MIN = 0, L_MAX = N; + final int R_MIN = 0, R_MAX = N; + out.print(N); out.print(' '); out.print(Q); out.print('\n'); + final int[] A = new int[N]; + for (int i = 0; i < N; i++) { + A[i] = rndIntClosedRange(A_MIN, A_MAX); + out.print(A[i]); + if (i < N - 1) { + out.print(' '); + } else { + out.print('\n'); + } + } + for (int i = 0; i < Q; i++) { + int type = rndIntClosedRange(QUERY_MIN, QUERY_MAX); + out.print(type); + if (type == 0) { // set + int p = rndIntClosedRange(P_MIN, P_MAX); + int v = rndIntClosedRange(V_MIN, V_MAX); + out.print(' ');out.print(p);out.print(' ');out.print(v);out.print('\n'); + } else if (type == 1) { // apply + int p = rndIntClosedRange(P_MIN, P_MAX); + int v = rndIntClosedRange(V_MIN, V_MAX); + out.print(' ');out.print(p);out.print(' ');out.print(v);out.print('\n'); + } else if (type == 2) { // apply + int l = rndIntClosedRange(L_MIN, L_MAX); + int r = rndIntClosedRange(R_MIN, R_MAX); + int v = rndIntClosedRange(V_MIN, V_MAX); + if (l > r) { + int tmp = l; l = r; r = tmp; + } + out.print(' ');out.print(l);out.print(' ');out.print(r);out.print(' ');out.print(v);out.print('\n'); + } else if (type == 3) { // get + int p = rndIntClosedRange(P_MIN, P_MAX); + out.print(' '); out.print(p);out.print('\n'); + } else if (type == 4) { // prod + int l = rndIntClosedRange(L_MIN, L_MAX); + int r = rndIntClosedRange(R_MIN, R_MAX); + if (l > r) { + int tmp = l; l = r; r = tmp; + } + out.print(' ');out.print(l);out.print(' ');out.print(r);out.print('\n'); + } else if (type == 5) { // prodAll + out.print('\n'); + } else if (type == 6) { // maxRight + int l = rndIntClosedRange(L_MIN, L_MAX); + int v = rndIntClosedRange(V_MIN, V_MAX); + out.print(' ');out.print(l);out.print(' ');out.print(v);out.print('\n'); + } else if (type == 7) { // minLeft + int r = rndIntClosedRange(R_MIN, R_MAX); + int v = rndIntClosedRange(V_MIN, V_MAX); + out.print(' ');out.print(r);out.print(' ');out.print(v);out.print('\n'); + } else { + throw new AssertionError(); + } + } + } + + public static int rndIntClosedRange(int l, int r) { + return rnd.nextInt(r - l + 1) + l; + } +} diff --git a/LazySegTree/test/Main.java b/LazySegTree/test/Main.java new file mode 100644 index 0000000..217a425 --- /dev/null +++ b/LazySegTree/test/Main.java @@ -0,0 +1,14 @@ +package test; + +public class Main { + public static void main(String[] args) { + test(); + } + + static void test() { + Gen.main(null); + NaiveSolution.main(null); + Solution.main(null); + Test.main(null); + } +} diff --git a/LazySegTree/test/NaiveSolution.java b/LazySegTree/test/NaiveSolution.java new file mode 100644 index 0000000..fc31631 --- /dev/null +++ b/LazySegTree/test/NaiveSolution.java @@ -0,0 +1,93 @@ +package test; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Scanner; + +public class NaiveSolution { + static final int TEST_CASE_NUM = Gen.TESTCASE_NUM; + public static void main(String[] args) { + for (int i = 0; i < TEST_CASE_NUM; i++) { + String inputFileName = String.format("LazySegTree/test/in/testcase_%d", i); + String outputFileName = String.format("LazySegTree/test/answer/answer_%d", i); + try (Scanner sc = new Scanner(new File(inputFileName))) { + try (PrintWriter pw = new PrintWriter(new File(outputFileName))) { + solve(sc, pw); + sc.close(); + pw.flush(); + pw.close(); + } + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + static final long INF = 1l << 60; + + public static void solve(Scanner sc, PrintWriter pw) { + final int N = Integer.parseInt(sc.next()); + final int Q = Integer.parseInt(sc.next()); + final long[] A = new long[N]; + Arrays.setAll(A, i -> Integer.parseInt(sc.next())); + for (int i = 0; i < Q; i++) { + int queryType = Integer.parseInt(sc.next()); + if (queryType == 0) { + int p = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + A[p] = v; + } else if (queryType == 1) { + int p = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + A[p] += v; + } else if (queryType == 2) { + int l = Integer.parseInt(sc.next()); + int r = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + for (int j = l; j < r; j++) { + A[j] += v; + } + } else if (queryType == 3) { + int p = Integer.parseInt(sc.next()); + pw.println(A[p]); + } else if (queryType == 4) { + int l = Integer.parseInt(sc.next()); + int r = Integer.parseInt(sc.next()); + long min = INF; + for (int j = l; j < r; j++) { + min = Math.min(min, A[j]); + } + pw.println(min == INF ? "INF" : min); + } else if (queryType == 5) { + long min = INF; + for (int j = 0; j < N; j++) { + min = Math.min(min, A[j]); + } + pw.println(min); + } else if (queryType == 6) { + int l = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + for (int j = l; j <= N; j++) { + if (j == N || A[j] <= v) { + pw.println(j); + break; + } + } + } else if (queryType == 7) { + int r = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + for (int j = r; j >= 0; j--) { + if (j == 0 || A[j - 1] <= v) { + pw.println(j); + break; + } + } + } else { + throw new AssertionError(); + } + } + } +} diff --git a/LazySegTree/test/Readme.md b/LazySegTree/test/Readme.md new file mode 100644 index 0000000..0dc54e8 --- /dev/null +++ b/LazySegTree/test/Readme.md @@ -0,0 +1,41 @@ +# Test of Lazy Segment Tree + +遅延評価セグメント木のテストです. + +- `Gen.java` : テストケースを LazySegTree/test/in 内に生成します. +- `NaiveSolution.java` : LazySegTree/test/in 内のテストを愚直に解いて,解答を LazySegTree/test/answer 内に生成します. +- `Solution.java` : LazySegTree/test/in 内のテストを遅延評価セグメント木を用いて解いて,解答を LazySegTree/test/out 内に生成します. +- `Test.java` : LazySegTree/test/answer 内の解答と LazySegTree/test/out 内の解答が一致しているかをテストします. +- `Main.java` : `Gen.java`,`NaiveSolution.java`,`Solution.java`,`Test.java` を順に実行します. + +## テスト概要 + +整数列 $A_0, \dots, A_{N-1}$ が与えられる.以下に示すクエリが合計 $Q$ 個与えられるので,順に処理する. + +- `0 p v` : $a_p = v$ とする. +- `1 p v` : $a_p$ に $v$ を加算する. +- `2 l r v` : $a_l, \dots, a_{r-1}$ に $v$ を加算する. +- `3 p` : $a_p$ の値を求めて出力する. +- `4 l r` : $\min\{a_i\mid l\leq i \lt r\}$ を求めて出力する.但し,$l=r$ の場合は `INF` と出力する. +- `5` : $\min\{a_i\mid 0\leq i \lt N\}$ を求めて出力する. +- `6 l v` : $\max\{r\mid\min\{a_i\mid l\leq i \lt r\}\gt v\}$ を求めて出力する.但し,$a_l\leq v$ なら $l$ を出力する. +- `7 r v` : $\min\{l\mid\min\{a_i\mid l\leq i \lt r\}\gt v\}$ を求めて出力する.但し,$a_{r-1}\leq v$ なら $r$ を出力する. + +## 制約 + +- $1\leq N \leq 5000$ +- $1\leq Q \leq 10000$ +- $-10^9\leq A_i\leq 10^9$ +- $-10^9\leq v\leq 10^9$ +- $0\leq p\lt N$ +- $0\leq l\leq r\leq N$ + +## 入力 + +```math +N Q +A_{0} \dots A_{N-1} +Query_{0} +\vdots +Query_{Q-1} +``` diff --git a/LazySegTree/test/Solution.java b/LazySegTree/test/Solution.java new file mode 100644 index 0000000..2ebaf00 --- /dev/null +++ b/LazySegTree/test/Solution.java @@ -0,0 +1,376 @@ +package test; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Scanner; + +public class Solution { + static final int TEST_CASE_NUM = Gen.TESTCASE_NUM; + public static void main(String[] args) { + for (int i = 0; i < TEST_CASE_NUM; i++) { + String inputFileName = String.format("LazySegTree/test/in/testcase_%d", i); + String outputFileName = String.format("LazySegTree/test/out/out_%d", i); + try (Scanner sc = new Scanner(new File(inputFileName))) { + try (PrintWriter pw = new PrintWriter(new File(outputFileName))) { + solve(sc, pw); + sc.close(); + pw.flush(); + pw.close(); + } + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + static final long INF = 1l << 60; + + public static void solve(Scanner sc, PrintWriter pw) { + final int N = Integer.parseInt(sc.next()); + final int Q = Integer.parseInt(sc.next()); + final Long[] A = new Long[N]; + Arrays.setAll(A, i -> Long.parseLong(sc.next())); + LazySegTree t = new LazySegTree(A, Long::min, INF, (s, f) -> s + f, (s, f) -> s + f, 0l); + for (int i = 0; i < Q; i++) { + int queryType = Integer.parseInt(sc.next()); + if (queryType == 0) { + int p = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + t.set(p, (long) v); + } else if (queryType == 1) { + int p = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + t.apply(p, (long) v); + } else if (queryType == 2) { + int l = Integer.parseInt(sc.next()); + int r = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + t.apply(l, r, (long) v); + } else if (queryType == 3) { + int p = Integer.parseInt(sc.next()); + pw.println(t.get(p)); + } else if (queryType == 4) { + int l = Integer.parseInt(sc.next()); + int r = Integer.parseInt(sc.next()); + long min = t.prod(l, r); + pw.println(min == INF ? "INF" : min); + } else if (queryType == 5) { + pw.println(t.allProd()); + } else if (queryType == 6) { + int l = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + pw.println(t.maxRight(l, val -> val > v)); + } else if (queryType == 7) { + int r = Integer.parseInt(sc.next()); + int v = Integer.parseInt(sc.next()); + pw.println(t.minLeft(r, val -> val > v)); + } else { + throw new AssertionError(); + } + } + } +} + +/** + * TODO: verify {@link LazySegTree#maxRight} and {@link LazySegTree#minLeft} + * + * @verified https://atcoder.jp/contests/practice2/tasks/practice2_k + */ + +class LazySegTree { + final int MAX; + + final int N; + final int Log; + final java.util.function.BinaryOperator Op; + final S E; + final java.util.function.BiFunction Mapping; + final java.util.function.BinaryOperator Composition; + final F Id; + + final S[] Dat; + final F[] Laz; + + @SuppressWarnings("unchecked") + public LazySegTree(int n, java.util.function.BinaryOperator op, S e, java.util.function.BiFunction mapping, java.util.function.BinaryOperator composition, F id) { + this.MAX = n; + int k = 1; + while (k < n) k <<= 1; + this.N = k; + this.Log = Integer.numberOfTrailingZeros(N); + this.Op = op; + this.E = e; + this.Mapping = mapping; + this.Composition = composition; + this.Id = id; + this.Dat = (S[]) new Object[N << 1]; + this.Laz = (F[]) new Object[N]; + java.util.Arrays.fill(Dat, E); + java.util.Arrays.fill(Laz, Id); + } + + public LazySegTree(S[] dat, java.util.function.BinaryOperator op, S e, java.util.function.BiFunction mapping, java.util.function.BinaryOperator composition, F id) { + this(dat.length, op, e, mapping, composition, id); + build(dat); + } + + private void build(S[] dat) { + int l = dat.length; + System.arraycopy(dat, 0, Dat, N, l); + for (int i = N - 1; i > 0; i--) { + Dat[i] = Op.apply(Dat[i << 1 | 0], Dat[i << 1 | 1]); + } + } + + private void push(int k) { + if (Laz[k] == Id) return; + int lk = k << 1 | 0, rk = k << 1 | 1; + Dat[lk] = Mapping.apply(Laz[k], Dat[lk]); + Dat[rk] = Mapping.apply(Laz[k], Dat[rk]); + if (lk < N) Laz[lk] = Composition.apply(Laz[k], Laz[lk]); + if (rk < N) Laz[rk] = Composition.apply(Laz[k], Laz[rk]); + Laz[k] = Id; + } + + private void pushTo(int k) { + for (int i = Log; i > 0; i--) push(k >> i); + } + + private void pushTo(int lk, int rk) { + for (int i = Log; i > 0; i--) { + if (((lk >> i) << i) != lk) push(lk >> i); + if (((rk >> i) << i) != rk) push(rk >> i); + } + } + + private void updateFrom(int k) { + k >>= 1; + while (k > 0) { + Dat[k] = Op.apply(Dat[k << 1 | 0], Dat[k << 1 | 1]); + k >>= 1; + } + } + + private void updateFrom(int lk, int rk) { + for (int i = 1; i <= Log; i++) { + if (((lk >> i) << i) != lk) { + int lki = lk >> i; + Dat[lki] = Op.apply(Dat[lki << 1 | 0], Dat[lki << 1 | 1]); + } + if (((rk >> i) << i) != rk) { + int rki = (rk - 1) >> i; + Dat[rki] = Op.apply(Dat[rki << 1 | 0], Dat[rki << 1 | 1]); + } + } + } + + public void set(int p, S x) { + exclusiveRangeCheck(p); + p += N; + pushTo(p); + Dat[p] = x; + updateFrom(p); + } + + public S get(int p) { + exclusiveRangeCheck(p); + p += N; + pushTo(p); + return Dat[p]; + } + + public S prod(int l, int r) { + if (l > r) { + throw new IllegalArgumentException( + String.format("Invalid range: [%d, %d)", l, r) + ); + } + inclusiveRangeCheck(l); + inclusiveRangeCheck(r); + if (l == r) return E; + l += N; r += N; + pushTo(l, r); + S sumLeft = E, sumRight = E; + while (l < r) { + if ((l & 1) == 1) sumLeft = Op.apply(sumLeft, Dat[l++]); + if ((r & 1) == 1) sumRight = Op.apply(Dat[--r], sumRight); + l >>= 1; r >>= 1; + } + return Op.apply(sumLeft, sumRight); + } + + public S allProd() { + return Dat[1]; + } + + public void apply(int p, F f) { + exclusiveRangeCheck(p); + p += N; + pushTo(p); + Dat[p] = Mapping.apply(f, Dat[p]); + updateFrom(p); + } + + public void apply(int l, int r, F f) { + if (l > r) { + throw new IllegalArgumentException( + String.format("Invalid range: [%d, %d)", l, r) + ); + } + inclusiveRangeCheck(l); + inclusiveRangeCheck(r); + if (l == r) return; + l += N; r += N; + pushTo(l, r); + for (int l2 = l, r2 = r; l2 < r2;) { + if ((l2 & 1) == 1) { + Dat[l2] = Mapping.apply(f, Dat[l2]); + if (l2 < N) Laz[l2] = Composition.apply(f, Laz[l2]); + l2++; + } + if ((r2 & 1) == 1) { + r2--; + Dat[r2] = Mapping.apply(f, Dat[r2]); + if (r2 < N) Laz[r2] = Composition.apply(f, Laz[r2]); + } + l2 >>= 1; r2 >>= 1; + } + updateFrom(l, r); + } + + public int maxRight(int l, java.util.function.Predicate g) { + inclusiveRangeCheck(l); + if (!g.test(E)) { + throw new IllegalArgumentException("Identity element must satisfy the condition."); + } + if (l == MAX) return MAX; + l += N; + pushTo(l); + S sum = E; + do { + l >>= Integer.numberOfTrailingZeros(l); + if (!g.test(Op.apply(sum, Dat[l]))) { + while (l < N) { + push(l); + l = l << 1; + if (g.test(Op.apply(sum, Dat[l]))) { + sum = Op.apply(sum, Dat[l]); + l++; + } + } + return l - N; + } + sum = Op.apply(sum, Dat[l]); + l++; + } while ((l & -l) != l); + return MAX; + } + + public int minLeft(int r, java.util.function.Predicate g) { + inclusiveRangeCheck(r); + if (!g.test(E)) { + throw new IllegalArgumentException("Identity element must satisfy the condition."); + } + if (r == 0) return 0; + r += N; + pushTo(r - 1); + S sum = E; + do { + r--; + while (r > 1 && (r & 1) == 1) r >>= 1; + if (!g.test(Op.apply(Dat[r], sum))) { + while (r < N) { + push(r); + r = r << 1 | 1; + if (g.test(Op.apply(Dat[r], sum))) { + sum = Op.apply(Dat[r], sum); + r--; + } + } + return r + 1 - N; + } + sum = Op.apply(Dat[r], sum); + } while ((r & -r) != r); + return 0; + } + + private void exclusiveRangeCheck(int p) { + if (p < 0 || p >= MAX) { + throw new IndexOutOfBoundsException( + String.format("Index %d is not in [%d, %d).", p, 0, MAX) + ); + } + } + + private void inclusiveRangeCheck(int p) { + if (p < 0 || p > MAX) { + throw new IndexOutOfBoundsException( + String.format("Index %d is not in [%d, %d].", p, 0, MAX) + ); + } + } + + // **************** DEBUG **************** // + + private int indent = 6; + + public void setIndent(int newIndent) { + this.indent = newIndent; + } + + @Override + public String toString() { + return toSimpleString(); + } + + private S[] simulatePushAll() { + S[] simDat = java.util.Arrays.copyOf(Dat, 2 * N); + F[] simLaz = java.util.Arrays.copyOf(Laz, 2 * N); + for (int k = 1; k < N; k++) { + if (simLaz[k] == Id) continue; + int lk = k << 1 | 0, rk = k << 1 | 1; + simDat[lk] = Mapping.apply(simLaz[k], simDat[lk]); + simDat[rk] = Mapping.apply(simLaz[k], simDat[rk]); + if (lk < N) simLaz[lk] = Composition.apply(simLaz[k], simLaz[lk]); + if (rk < N) simLaz[rk] = Composition.apply(simLaz[k], simLaz[rk]); + simLaz[k] = Id; + } + return simDat; + } + + public String toDetailedString() { + return toDetailedString(1, 0, simulatePushAll()); + } + + private String toDetailedString(int k, int sp, S[] dat) { + if (k >= N) return indent(sp) + dat[k]; + String s = ""; + s += toDetailedString(k << 1 | 1, sp + indent, dat); + s += "\n"; + s += indent(sp) + dat[k]; + s += "\n"; + s += toDetailedString(k << 1 | 0, sp + indent, dat); + return s; + } + + private static String indent(int n) { + StringBuilder sb = new StringBuilder(); + while (n --> 0) sb.append(' '); + return sb.toString(); + } + + public String toSimpleString() { + S[] dat = simulatePushAll(); + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (int i = 0; i < N; i++) { + sb.append(dat[i + N]); + if (i < N - 1) sb.append(',').append(' '); + } + sb.append(']'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/LazySegTree/test/Test.java b/LazySegTree/test/Test.java new file mode 100644 index 0000000..44a1db1 --- /dev/null +++ b/LazySegTree/test/Test.java @@ -0,0 +1,41 @@ +package test; + +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + +public class Test { + static final int TEST_CASE_NUM = Gen.TESTCASE_NUM; + + public static void main(String[] args) { + for (int i = 0; i < TEST_CASE_NUM; i++) { + String answerFileName = String.format("LazySegTree/test/answer/answer_%d", i); + String outputFileName = String.format("LazySegTree/test/out/out_%d", i); + try (Scanner scAns = new Scanner(new File(answerFileName))) { + try (Scanner scSlv = new Scanner(new File(outputFileName))) { + test(scAns, scSlv); + } catch (AssertionError e) { + System.err.printf("Error in test %d", i); + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + public static void test(Scanner scAns, Scanner scSlv) { + int line = 1; + while (scAns.hasNext() && scSlv.hasNext()) { + String ans = scAns.next(); + String slv = scSlv.next(); + if (!ans.equals(slv)) { + throw new AssertionError( + String.format("Filed at line %d.\n\texpected: %s\n\tactual: %s", line, ans, slv) + ); + } + line++; + } + } +} From 6a7db2aebce81bc007350d2443677959d3524398 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 01:39:12 +0530 Subject: [PATCH 06/48] Created GraphBuilder.java This file add utilities for building graph in form of jagged arrays, as opposed to ArrayLists, offering comparatively better performance. --- GraphBuilder/GraphBuilder.java | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 GraphBuilder/GraphBuilder.java diff --git a/GraphBuilder/GraphBuilder.java b/GraphBuilder/GraphBuilder.java new file mode 100644 index 0000000..f27f3de --- /dev/null +++ b/GraphBuilder/GraphBuilder.java @@ -0,0 +1,59 @@ +class GraphBuilder{ + public int[][] makeGraph(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ + int[][] graph = new int[NumberOfNoes][]; + int[] outdegree = new int[NumberOfNoes]; + for(int i = 0; i< NumberOfEdges; i++){ + outdegree[from[i]]++; + if(undirected)outdegree[to[i]]++; + } + for(int i = 0; i< NumberOfNoes; i++)graph[i] = new int[outdegree[i]]; + for(int i = 0; i< NumberOfEdges; i++){ + graph[from[i]][--outdegree[from[i]]] = to[i]; + if(undirected)graph[to[i]][--outdegree[to[i]]] = from[i]; + } + return graph; + } + + public int[][][] makeGraphWithEdgeInfo(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ + int[][][] graph = new int[NumberOfNoes][][]; + int[] outdegree = new int[NumberOfNoes]; + for(int i = 0; i< NumberOfEdges; i++){ + outdegree[from[i]]++; + if(undirected)outdegree[to[i]]++; + } + for(int i = 0; i< NumberOfNoes; i++)graph[i] = new int[outdegree[i]][]; + for(int i = 0; i< NumberOfEdges; i++){ + graph[from[i]][--outdegree[from[i]]] = new int[]{to[i], i, 0}; + if(undirected)graph[to[i]][--outdegree[to[i]]] = new int[]{from[i], i, 1}; + } + return graph; + } + + //Usage Exmaple + public void makeGraphUsage(){ + int N = 6, E = 8; + int[] from = new int[]{0,0,0,1,1,2,2,4}; + int[] to = new int[]{2,4,5,4,5,3,4,5}; + + int[][] graph = makeGraph(N, E, from, to, true); + for(int i = 0; i< N; i++){ + System.out.print(i+": "); + for(int j:graph[i])System.out.print(j+" "); + System.out.println(); + } + } + + //Usage Example + public void makeGraphWithEdgeInfoUsage(){ + int N = 6, E = 8; + int[] from = new int[]{0,0,0,1,1,2,2,4}; + int[] to = new int[]{2,4,5,4,5,3,4,5}; + + int[][][] graph = makeGraphWithEdgeInfo(N, E, from, to, true); + for(int i = 0; i< N; i++){ + System.out.print(i+": "); + for(int[] j:graph[i])System.out.print("["+j[0]+", "+j[1]+", "+j[2]+"],"); + System.out.println(); + } + } +} From 36308c5c996402128e2a14e58bac112a2780d00f Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 01:50:41 +0530 Subject: [PATCH 07/48] Updated GraphBuilder.java Moved example usage to separate file, modified access specifies and made methods static. --- GraphBuilder/GraphBuilder.java | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/GraphBuilder/GraphBuilder.java b/GraphBuilder/GraphBuilder.java index f27f3de..a8d90e6 100644 --- a/GraphBuilder/GraphBuilder.java +++ b/GraphBuilder/GraphBuilder.java @@ -1,5 +1,5 @@ class GraphBuilder{ - public int[][] makeGraph(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ + public static int[][] makeGraph(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ int[][] graph = new int[NumberOfNoes][]; int[] outdegree = new int[NumberOfNoes]; for(int i = 0; i< NumberOfEdges; i++){ @@ -14,7 +14,7 @@ public int[][] makeGraph(int NumberOfNoes, int NumberOfEdges, int[] from, int[] return graph; } - public int[][][] makeGraphWithEdgeInfo(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ + public static int[][][] makeGraphWithEdgeInfo(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ int[][][] graph = new int[NumberOfNoes][][]; int[] outdegree = new int[NumberOfNoes]; for(int i = 0; i< NumberOfEdges; i++){ @@ -28,32 +28,4 @@ public int[][][] makeGraphWithEdgeInfo(int NumberOfNoes, int NumberOfEdges, int[ } return graph; } - - //Usage Exmaple - public void makeGraphUsage(){ - int N = 6, E = 8; - int[] from = new int[]{0,0,0,1,1,2,2,4}; - int[] to = new int[]{2,4,5,4,5,3,4,5}; - - int[][] graph = makeGraph(N, E, from, to, true); - for(int i = 0; i< N; i++){ - System.out.print(i+": "); - for(int j:graph[i])System.out.print(j+" "); - System.out.println(); - } - } - - //Usage Example - public void makeGraphWithEdgeInfoUsage(){ - int N = 6, E = 8; - int[] from = new int[]{0,0,0,1,1,2,2,4}; - int[] to = new int[]{2,4,5,4,5,3,4,5}; - - int[][][] graph = makeGraphWithEdgeInfo(N, E, from, to, true); - for(int i = 0; i< N; i++){ - System.out.print(i+": "); - for(int[] j:graph[i])System.out.print("["+j[0]+", "+j[1]+", "+j[2]+"],"); - System.out.println(); - } - } } From 7cf55d7907ba66bb23cdd47de954151378391655 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 01:54:18 +0530 Subject: [PATCH 08/48] Created GraphBuilderUsage.java This file illustrates the sample usage of GraphBuilder.java --- GraphBuilder/GraphBuilderUsage.java | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 GraphBuilder/GraphBuilderUsage.java diff --git a/GraphBuilder/GraphBuilderUsage.java b/GraphBuilder/GraphBuilderUsage.java new file mode 100644 index 0000000..cc38c57 --- /dev/null +++ b/GraphBuilder/GraphBuilderUsage.java @@ -0,0 +1,34 @@ +class GraphBuilderUsage{ + //Usage Exmaple + public static void makeGraphUsage(){ + int N = 6, E = 8; + int[] from = new int[]{0,0,0,1,1,2,2,4}; + int[] to = new int[]{2,4,5,4,5,3,4,5}; + + int[][] graph = GraphBuilder.makeGraph(N, E, from, to, true); + for(int i = 0; i< N; i++){ + System.out.print(i+": "); + for(int j:graph[i])System.out.print(j+" "); + System.out.println(); + } + } + + //Usage Example + public static void makeGraphWithEdgeInfoUsage(){ + int N = 6, E = 8; + int[] from = new int[]{0,0,0,1,1,2,2,4}; + int[] to = new int[]{2,4,5,4,5,3,4,5}; + + int[][][] graph = GraphBuilder.makeGraphWithEdgeInfo(N, E, from, to, true); + for(int i = 0; i< N; i++){ + System.out.print(i+": "); + for(int[] j:graph[i])System.out.print("["+j[0]+", "+j[1]+", "+j[2]+"],"); + System.out.println(); + } + } + + public static void main(String[] args){ + makeGraphUsage(); + makeGraphWithEdgeInfoUsage(); + } +} From 5d5042d96e9176372ed566c29acc6266c7a844ad Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 02:10:13 +0530 Subject: [PATCH 09/48] Corrected Typo in variable name --- GraphBuilder/GraphBuilder.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/GraphBuilder/GraphBuilder.java b/GraphBuilder/GraphBuilder.java index a8d90e6..95a4be8 100644 --- a/GraphBuilder/GraphBuilder.java +++ b/GraphBuilder/GraphBuilder.java @@ -1,12 +1,12 @@ class GraphBuilder{ - public static int[][] makeGraph(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ - int[][] graph = new int[NumberOfNoes][]; - int[] outdegree = new int[NumberOfNoes]; + public static int[][] makeGraph(int NumberOfNodes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ + int[][] graph = new int[NumberOfNodes][]; + int[] outdegree = new int[NumberOfNodes]; for(int i = 0; i< NumberOfEdges; i++){ outdegree[from[i]]++; if(undirected)outdegree[to[i]]++; } - for(int i = 0; i< NumberOfNoes; i++)graph[i] = new int[outdegree[i]]; + for(int i = 0; i< NumberOfNodes; i++)graph[i] = new int[outdegree[i]]; for(int i = 0; i< NumberOfEdges; i++){ graph[from[i]][--outdegree[from[i]]] = to[i]; if(undirected)graph[to[i]][--outdegree[to[i]]] = from[i]; @@ -14,14 +14,14 @@ public static int[][] makeGraph(int NumberOfNoes, int NumberOfEdges, int[] from, return graph; } - public static int[][][] makeGraphWithEdgeInfo(int NumberOfNoes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ - int[][][] graph = new int[NumberOfNoes][][]; - int[] outdegree = new int[NumberOfNoes]; + public static int[][][] makeGraphWithEdgeInfo(int NumberOfNodes, int NumberOfEdges, int[] from, int[] to, boolean undirected){ + int[][][] graph = new int[NumberOfNodes][][]; + int[] outdegree = new int[NumberOfNodes]; for(int i = 0; i< NumberOfEdges; i++){ outdegree[from[i]]++; if(undirected)outdegree[to[i]]++; } - for(int i = 0; i< NumberOfNoes; i++)graph[i] = new int[outdegree[i]][]; + for(int i = 0; i< NumberOfNodes; i++)graph[i] = new int[outdegree[i]][]; for(int i = 0; i< NumberOfEdges; i++){ graph[from[i]][--outdegree[from[i]]] = new int[]{to[i], i, 0}; if(undirected)graph[to[i]][--outdegree[to[i]]] = new int[]{from[i], i, 1}; From 4e41ed60c7a0eb6acfa71dc0f5f3440334889f1a Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 02:28:47 +0530 Subject: [PATCH 10/48] Added README.md --- GraphBuilder/README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 GraphBuilder/README.md diff --git a/GraphBuilder/README.md b/GraphBuilder/README.md new file mode 100644 index 0000000..22fa59c --- /dev/null +++ b/GraphBuilder/README.md @@ -0,0 +1,40 @@ +# Class GraphBuilder + +Creates graph in form of jagged arrays (as compared to Arraylist) for directed as well as undirected graphs from given set of edges in 0 indexing. + +All members of this class are static, so no constructor defined. + +## Methods + +### makeGraph +``` +public static int[][] makeGraph(int NumberOfNodes, int NumberOfEdges, int[] from, int[] to, boolean undirected) +``` +Returns the adjacency list representation of graph with specified Number of Nodes and Edges and the edges specified in from and to arrays in 0-based indexing. If undirected is set to true, the edges are deemed to be undirected, otherwise directed. + +```graph[u]``` is the array of vertices having an edge outgoing from vertex u. + +** Constraints ** +* 0 \leq from[i], to[i] < NumberOfNodes +* from.length = to.length = NumberOfEdges + +** Computational complexity ** +* $ O (NumberOfNodes + NumberOfEdges) $ + +### makeGraphWithEdgeInfo +``` +public static int[][][] makeGraphWithEdgeInfo(int NumberOfNodes, int NumberOfEdges, int[] from, int[] to, boolean undirected) +``` + +Returns the adjacency list representation of graph with specified Number of Nodes and Edges and the edges specified in from and to arrays in 0-based indexing. If undirected is set to true, the edges are deemed to be undirected, otherwise directed. This method also returns useful information about edge index and edge direction. + +```graph[u]``` is the array of tuples ```[v, idx, direction]``` where edge indexed ```idx``` is between node ```u``` and node ```v``` and direction takes value either $0$ or $1$. +- If direction is $0$, edge indexed ```idx``` is from ```u``` to ```v``` +- If direction is $1$, edge indexed ```idx``` is from ```v``` to ```u``` + +** Constraints ** +* 0 \leq from[i], to[i] < NumberOfNodes +* from.length = to.length = NumberOfEdges + +** Computational complexity ** +* $ O (NumberOfNodes + NumberOfEdges) $ From 1fc96de64dd88c0a67e55cee89c86c0f001b51ad Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 17:35:57 +0530 Subject: [PATCH 11/48] Created ArticulationPoint.java Created ArticulationPoint.java, expects graph to be generated in accordance with GraphBuilder makeGraph method. --- ArticulationPoint/ArticulationPoint.java | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 ArticulationPoint/ArticulationPoint.java diff --git a/ArticulationPoint/ArticulationPoint.java b/ArticulationPoint/ArticulationPoint.java new file mode 100644 index 0000000..a28f680 --- /dev/null +++ b/ArticulationPoint/ArticulationPoint.java @@ -0,0 +1,37 @@ +class ArticulationPoints{ + private static int time; + private static int[] disc, low; + private static boolean[] visited; + + public static boolean[] articulationPoints(int[][] graph){ + int NumberOfNodes = graph.length; + + time = -1; + disc = new int[NumberOfNodes]; + low = new int[NumberOfNodes]; + visited = new boolean[NumberOfNodes]; + java.util.Arrays.fill(low, 2*NumberOfNodes); + + boolean[] isAP = new boolean[NumberOfNodes]; + for(int i = 0; i< NumberOfNodes; i++)if(!visited[i] && graph[i] != null)apUtil(graph, isAP, i, -1); + return isAP; + } + + private static void apUtil(int[][] g, boolean[] isAP, int u, int p){ + visited[u] = true; + disc[u] = low[u] = ++time; + + int childCount = 0; + for(int v:g[u]){ + if(!visited[v]){ + apUtil(g, isAP, v, u); + + low[u] = Math.min(low[u], low[v]); + childCount++; + + if(p != -1 && low[v] >= disc[u])isAP[u] = true; + }else if(v != p)low[u] = Math.min(low[u], disc[v]); + } + if(p == -1 && childCount > 1)isAP[u] = true; + } +} From d05be774dec5ebad7713bae0eac940ec98a8b6e4 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 17:39:41 +0530 Subject: [PATCH 12/48] Created ArticulationPointsUsage.java Illustrates the usage of ArticulationPoint.articulationPoints() method. --- .../ArticulationPointsUsage.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 ArticulationPoint/ArticulationPointsUsage.java diff --git a/ArticulationPoint/ArticulationPointsUsage.java b/ArticulationPoint/ArticulationPointsUsage.java new file mode 100644 index 0000000..4621622 --- /dev/null +++ b/ArticulationPoint/ArticulationPointsUsage.java @@ -0,0 +1,20 @@ +class ArticulationPointsUsage{ + //Usage example ArticulationPoint.articulationPoints() + public static void articulationPointsUsage(){ + int N = 6, E = 6; + int[] from = new int[]{0,1,1,2,2,4}; + int[] to = new int[]{5,4,5,3,4,5}; + + int[][] graph = GraphBuilder.makeGraph(N, E, from, to, true); + boolean[] articulationPoint = ArticulationPoints.articulationPoints(graph); + + for(int i = 0; i< N; i++){ + if(articulationPoint[i]) + System.out.println(i+" is an articulation point"); + } + } + + public static void main(String[] args){ + articulationPointsUsage(); + } +} From 3c3dceeec7c9b7b3e685ec3b5b806ddd76f21a37 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 17:49:11 +0530 Subject: [PATCH 13/48] Added README.md Added Explanation for ArticulationPoint.java --- ArticulationPoint/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 ArticulationPoint/README.md diff --git a/ArticulationPoint/README.md b/ArticulationPoint/README.md new file mode 100644 index 0000000..5bc1ff8 --- /dev/null +++ b/ArticulationPoint/README.md @@ -0,0 +1,19 @@ +# Class ArticulationPoint + +Given a graph generated using GraphBuilder.makeGraph(), this class finds all articulation points in graph. Since GraphBuilder assumes 0-based indexing, this class also works assuming 0-based indexing. + +All members of this class are static, so no constructor defined. + +## Methods + +### articulationPoints +``` +public static boolean[] articulationPoints(int[][] graph) +``` +Returns boolean array of length $N$ where $N$ denotes the number of nodes in given graph, i-th element in this boolean array denotes whether i-th node in given graph is an articulation point or not. + +** Constraints ** +* graph is generated using GraphBuilder.makeGraph(), so all constraints applicable to makeGraph method applies. + +** Computational complexity ** +* $ O (NumberOfNodes + NumberOfEdges) $ From 1f63336c03428200cc2ee53815fa2e22cc8d55be Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 18:09:50 +0530 Subject: [PATCH 14/48] Created Bridge.java This class finds all bridges in given Graph. --- Bridge/Bridge.java | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Bridge/Bridge.java diff --git a/Bridge/Bridge.java b/Bridge/Bridge.java new file mode 100644 index 0000000..d2e641a --- /dev/null +++ b/Bridge/Bridge.java @@ -0,0 +1,38 @@ +class Bridge{ + private static int time; + private static int[] disc, low; + private static boolean[] visited; + + public static boolean[] bridges(int[][][] graphWithEdgeInfo, int EdgeCount){ + int NumberOfNodes = graphWithEdgeInfo.length; + + time = -1; + disc = new int[NumberOfNodes]; + low = new int[NumberOfNodes]; + visited = new boolean[NumberOfNodes]; + java.util.Arrays.fill(low, 2*NumberOfNodes); + + boolean[] isBridge = new boolean[EdgeCount]; + for(int i = 0; i< NumberOfNodes; i++)if(!visited[i] && graphWithEdgeInfo[i] != null)bridgeUtil(graphWithEdgeInfo, isBridge, i, -1); + return isBridge; + } + + private static void bridgeUtil(int[][][] g, boolean[] isBridge, int u, int p){ + visited[u] = true; + disc[u] = low[u] = ++time; + + for(int[] edge: g[u]){ + int v = edge[0], edgeIndex = edge[1]; + if(v == p)continue; + + if(visited[v]) + low[u] = Math.min(low[u], disc[v]); + else{ + bridgeUtil(g, isBridge, v, u); + low[u] = Math.min(low[u], low[v]); + + if(low[v] > disc[u])isBridge[edgeIndex] = true; + } + } + } +} From 97fa59bb4924339b9c2891f15c19f14b085cd3ce Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 18:12:46 +0530 Subject: [PATCH 15/48] Created BridgeUsage.java Illustrates the usage of Bridge class --- Bridge/BridgeUsage.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Bridge/BridgeUsage.java diff --git a/Bridge/BridgeUsage.java b/Bridge/BridgeUsage.java new file mode 100644 index 0000000..78db4bc --- /dev/null +++ b/Bridge/BridgeUsage.java @@ -0,0 +1,20 @@ +class BridgeUsage{ + //Usage Example Bridge.bridges() + public static void bridgesUsage(){ + int N = 6, E = 6; + int[] from = new int[]{0,1,1,2,2,4}; + int[] to = new int[]{5,4,5,3,4,5}; + + int[][][] graph = GraphBuilder.makeGraphWithEdgeInfo(N, E, from, to, true); + boolean[] isBridge = Bridge.bridges(graph, E); + + for(int i = 0; i< E; i++){ + if(isBridge[i]) + System.out.println(from[i] + " - " + to[i] + " is a bridge"); + } + } + + public static void main(String[] args){ + bridgesUsage(); + } +} From 5108b61a666a077d5edc3ccfb263e8cf8d0af9d2 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Fri, 2 Oct 2020 18:17:28 +0530 Subject: [PATCH 16/48] Added README.md Added README for Bridge.java class --- Bridge/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Bridge/README.md diff --git a/Bridge/README.md b/Bridge/README.md new file mode 100644 index 0000000..56c7bdf --- /dev/null +++ b/Bridge/README.md @@ -0,0 +1,20 @@ +# Class Bridge + +Given a graph generated using GraphBuilder.makeGraphWithEdgeInfo(), this class finds all bridges in graph. Since GraphBuilder assumes 0-based indexing, this class also works assuming 0-based indexing. + +All members of this class are static, so no constructor defined. + +## Methods + +### bridges +``` +public static boolean[] bridges(int[][][] graphWithEdgeInfo, int EdgeCount) +``` +Returns boolean array of length $EdgeCount$ where $EdgeCount$ denotes the number of edges in given graph, i-th element in this boolean array denotes whether i-th edge in given graph is a bridge or not. The edges are numbered as per their order in input, defined in GraphBuilder.makeGraphWithEdgeInfo() + +** Constraints ** +* graph is generated using GraphBuilder.makeGraphWithEdgeInfo(), so all constraints applicable to makeGraphWithEdgeInfo method applies. +* EdgeCount = Number of edges specified in GraphBuilder.makeGraphWithEdgeInfo() + +** Computational complexity ** +* $ O (NumberOfNodes + NumberOfEdges) $ From 0e588f8ece6df579f661f4487cb8ec39caa44d23 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Sat, 3 Oct 2020 11:40:03 +0530 Subject: [PATCH 17/48] Updated Bridge.java Added support for multi-edges and self loops. --- Bridge/Bridge.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Bridge/Bridge.java b/Bridge/Bridge.java index d2e641a..affbde7 100644 --- a/Bridge/Bridge.java +++ b/Bridge/Bridge.java @@ -2,8 +2,14 @@ class Bridge{ private static int time; private static int[] disc, low; private static boolean[] visited; - - public static boolean[] bridges(int[][][] graphWithEdgeInfo, int EdgeCount){ + + public static boolean[] bridges(int[][][] graphWithEdgeInfo){ + int edgeCount = 0; + for(int[][] v:graphWithEdgeInfo)edgeCount += v.length; + return bridges(graphWithEdgeInfo, edgeCount); + } + + public static boolean[] bridges(int[][][] graphWithEdgeInfo, int edgeCount){ int NumberOfNodes = graphWithEdgeInfo.length; time = -1; @@ -12,23 +18,23 @@ public static boolean[] bridges(int[][][] graphWithEdgeInfo, int EdgeCount){ visited = new boolean[NumberOfNodes]; java.util.Arrays.fill(low, 2*NumberOfNodes); - boolean[] isBridge = new boolean[EdgeCount]; + boolean[] isBridge = new boolean[edgeCount]; for(int i = 0; i< NumberOfNodes; i++)if(!visited[i] && graphWithEdgeInfo[i] != null)bridgeUtil(graphWithEdgeInfo, isBridge, i, -1); return isBridge; } - private static void bridgeUtil(int[][][] g, boolean[] isBridge, int u, int p){ + private static void bridgeUtil(int[][][] g, boolean[] isBridge, int u, int parentEdge){ visited[u] = true; disc[u] = low[u] = ++time; for(int[] edge: g[u]){ int v = edge[0], edgeIndex = edge[1]; - if(v == p)continue; + if(parentEdge == edgeIndex)continue; if(visited[v]) low[u] = Math.min(low[u], disc[v]); else{ - bridgeUtil(g, isBridge, v, u); + bridgeUtil(g, isBridge, v, edgeIndex); low[u] = Math.min(low[u], low[v]); if(low[v] > disc[u])isBridge[edgeIndex] = true; From 4b5e0b5ba4c8a2869a31b3f860f2399164a12cad Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Sat, 3 Oct 2020 11:42:52 +0530 Subject: [PATCH 18/48] Updated Bridge.java Fixed typo in edgeCount, line 9. --- Bridge/Bridge.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bridge/Bridge.java b/Bridge/Bridge.java index affbde7..a101de8 100644 --- a/Bridge/Bridge.java +++ b/Bridge/Bridge.java @@ -5,8 +5,8 @@ class Bridge{ public static boolean[] bridges(int[][][] graphWithEdgeInfo){ int edgeCount = 0; - for(int[][] v:graphWithEdgeInfo)edgeCount += v.length; - return bridges(graphWithEdgeInfo, edgeCount); + for(int[][] row:graphWithEdgeInfo)edgeCount += row.length; + return bridges(graphWithEdgeInfo, edgeCount/2); } public static boolean[] bridges(int[][][] graphWithEdgeInfo, int edgeCount){ From fa646ea6381275588864ec069c2cd097073fb822 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Sat, 3 Oct 2020 11:54:36 +0530 Subject: [PATCH 19/48] Updated README.md Added explanation for boolean[] bridges(int[][][] graphWithEdgeInfo) --- Bridge/README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Bridge/README.md b/Bridge/README.md index 56c7bdf..08594c6 100644 --- a/Bridge/README.md +++ b/Bridge/README.md @@ -1,6 +1,6 @@ # Class Bridge -Given a graph generated using GraphBuilder.makeGraphWithEdgeInfo(), this class finds all bridges in graph. Since GraphBuilder assumes 0-based indexing, this class also works assuming 0-based indexing. +Given an undirected graph generated using GraphBuilder.makeGraphWithEdgeInfo(), this class finds all bridges in graph. Since GraphBuilder assumes 0-based indexing, this class also works assuming 0-based indexing. This class can handle multi-edges as well as self loops. All members of this class are static, so no constructor defined. @@ -8,13 +8,25 @@ All members of this class are static, so no constructor defined. ### bridges ``` -public static boolean[] bridges(int[][][] graphWithEdgeInfo, int EdgeCount) +public static boolean[] bridges(int[][][] graphWithEdgeInfo, int edgeCount) ``` -Returns boolean array of length $EdgeCount$ where $EdgeCount$ denotes the number of edges in given graph, i-th element in this boolean array denotes whether i-th edge in given graph is a bridge or not. The edges are numbered as per their order in input, defined in GraphBuilder.makeGraphWithEdgeInfo() +Returns boolean array of length $edgeCount$ where $EdgeCount$ denotes the number of edges in given graph, i-th element in this boolean array denotes whether i-th edge in given graph is a bridge or not. The edges are numbered as per their order in input, defined in GraphBuilder.makeGraphWithEdgeInfo() + +** Constraints ** +* graph is generated using GraphBuilder.makeGraphWithEdgeInfo(), so all constraints applicable to makeGraphWithEdgeInfo method applies. +* edgeCount = Number of edges specified in GraphBuilder.makeGraphWithEdgeInfo() + +** Computational complexity ** +* $ O (NumberOfNodes + NumberOfEdges) $ + + +``` +public static boolean[] bridges(int[][][] graphWithEdgeInfo) +``` +This method computed the number of edges in specified graph, and invokes ```boolean[] bridges(int[][][] graphWithEdgeInfo, int edgeCount)``` to return boolean array, i-th element in this boolean array denotes whether i-th edge in given graph is a bridge or not. ** Constraints ** * graph is generated using GraphBuilder.makeGraphWithEdgeInfo(), so all constraints applicable to makeGraphWithEdgeInfo method applies. -* EdgeCount = Number of edges specified in GraphBuilder.makeGraphWithEdgeInfo() ** Computational complexity ** * $ O (NumberOfNodes + NumberOfEdges) $ From 8c7ed6e952d0bb35700b2f86b96f779091be4c31 Mon Sep 17 00:00:00 2001 From: Taranpreet Singh <47025523+taran-1407@users.noreply.github.com> Date: Sat, 3 Oct 2020 12:01:55 +0530 Subject: [PATCH 20/48] Updated BridgeUsage.java Added multi-edges and self loops in example --- Bridge/BridgeUsage.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Bridge/BridgeUsage.java b/Bridge/BridgeUsage.java index 78db4bc..c5b5342 100644 --- a/Bridge/BridgeUsage.java +++ b/Bridge/BridgeUsage.java @@ -1,12 +1,12 @@ class BridgeUsage{ //Usage Example Bridge.bridges() public static void bridgesUsage(){ - int N = 6, E = 6; - int[] from = new int[]{0,1,1,2,2,4}; - int[] to = new int[]{5,4,5,3,4,5}; + int N = 6, E = 9; + int[] from = new int[]{0,1,1,2,2,4,4,3,1}; + int[] to = new int[]{5,4,5,3,4,5,4,2,4}; int[][][] graph = GraphBuilder.makeGraphWithEdgeInfo(N, E, from, to, true); - boolean[] isBridge = Bridge.bridges(graph, E); + boolean[] isBridge = Bridge.bridges(graph); for(int i = 0; i< E; i++){ if(isBridge[i]) From bc8a574a718396efcaa4dc2819a00dd9e28b128a Mon Sep 17 00:00:00 2001 From: NASU41 Date: Sat, 19 Dec 2020 23:00:02 +0900 Subject: [PATCH 21/48] add Fenwick::set/get add new functions: set(int p, long x) and get(int p). I implemented this because I needed them on ABC186. --- FenwickTree/FenwickTree.java | 8 ++++++++ FenwickTree/README.md | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/FenwickTree/FenwickTree.java b/FenwickTree/FenwickTree.java index 53aecd7..c896ad9 100644 --- a/FenwickTree/FenwickTree.java +++ b/FenwickTree/FenwickTree.java @@ -16,6 +16,10 @@ public FenwickTree(long[] data) { build(data); } + public void set(int p, long x){ + add(p, x - get(p)); + } + public void add(int p, long x){ assert(0<=p && p<_n); p++; @@ -29,6 +33,10 @@ public long sum(int l, int r){ return sum(r)-sum(l); } + public long get(int p){ + return sum(p, p+1); + } + private long sum(int r){ long s = 0; while(r>0){ diff --git a/FenwickTree/README.md b/FenwickTree/README.md index bcbe624..37723ea 100644 --- a/FenwickTree/README.md +++ b/FenwickTree/README.md @@ -32,6 +32,19 @@ public void add(int p, long x) 配列の第$p$要素に$x$を加える. すなわち, `a[p] += x` のこと. 計算量: $O(\log N)$ +### set +```java +public void set(int p, long x) +``` +配列の第$p$要素を$x$に変更する. すなわち, `a[p] = x` のこと. +計算量: $O(\log N)$ + +### get +```java +public long get(int p) +``` +配列の第$p$要素を取得する. 計算量: $O(\log n)$ + ### sum ```java public long sum(int l, int r) From 761ce2dbf9a60fe514b6e2d45db730ff114bc252 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Sun, 20 Dec 2020 02:02:34 +0900 Subject: [PATCH 22/48] Fix Readme of SegTree#prod --- SegTree/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SegTree/Readme.md b/SegTree/Readme.md index d0609eb..3faa914 100644 --- a/SegTree/Readme.md +++ b/SegTree/Readme.md @@ -68,7 +68,7 @@ public S prod(int l, int r) `op(a[l], ..., a[r - 1])` を、モノイドの性質を満たしていると仮定して計算します。`l = r` のときは単位元 `e` を返します。 -計算量: $O(n)$ +計算量: $O(\log n)$ 制約: `0 <= l <= r <= n` From 72bf8a8fce4d7089454d98da28f6a19584a039b6 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Sun, 20 Dec 2020 02:16:42 +0900 Subject: [PATCH 23/48] Modified internal implementation --- ModInt/ModInt.java | 860 +++++++++++++++++++++------------------------ 1 file changed, 394 insertions(+), 466 deletions(-) diff --git a/ModInt/ModInt.java b/ModInt/ModInt.java index c5850d8..0536dde 100644 --- a/ModInt/ModInt.java +++ b/ModInt/ModInt.java @@ -1,467 +1,395 @@ -/** - * @verified - *
    - *
  • https://atcoder.jp/contests/arc050/tasks/arc050_c - *
  • https://atcoder.jp/contests/abc129/tasks/abc129_f - *
- */ -class ModIntFactory { - private final ModArithmetic ma; - private final int mod; - - public ModIntFactory(int mod) { - this.ma = ModArithmetic.of(mod); - this.mod = mod; - } - - public ModInt create(long value) { - if ((value %= mod) < 0) value += mod; - if (ma instanceof ModArithmetic.ModArithmeticMontgomery) { - return new ModInt(((ModArithmetic.ModArithmeticMontgomery) ma).generate(value)); - } - return new ModInt((int) value); - } - - class ModInt { - private int value; - private ModInt(int value) { - this.value = value; - } - public int mod() { - return mod; - } - public int value() { - if (ma instanceof ModArithmetic.ModArithmeticMontgomery) { - return ((ModArithmetic.ModArithmeticMontgomery) ma).reduce(value); - } - return value; - } - public ModInt add(ModInt mi) { - return new ModInt(ma.add(value, mi.value)); - } - public ModInt add(ModInt mi1, ModInt mi2) { - return new ModInt(ma.add(value, mi1.value)).addAsg(mi2); - } - public ModInt add(ModInt mi1, ModInt mi2, ModInt mi3) { - return new ModInt(ma.add(value, mi1.value)).addAsg(mi2).addAsg(mi3); - } - public ModInt add(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { - return new ModInt(ma.add(value, mi1.value)).addAsg(mi2).addAsg(mi3).addAsg(mi4); - } - public ModInt add(ModInt mi1, ModInt... mis) { - ModInt mi = add(mi1); - for (ModInt m : mis) mi.addAsg(m); - return mi; - } - public ModInt add(long mi) { - return new ModInt(ma.add(value, ma.remainder(mi))); - } - public ModInt sub(ModInt mi) { - return new ModInt(ma.sub(value, mi.value)); - } - public ModInt sub(long mi) { - return new ModInt(ma.sub(value, ma.remainder(mi))); - } - public ModInt mul(ModInt mi) { - return new ModInt(ma.mul(value, mi.value)); - } - public ModInt mul(ModInt mi1, ModInt mi2) { - return new ModInt(ma.mul(value, mi1.value)).mulAsg(mi2); - } - public ModInt mul(ModInt mi1, ModInt mi2, ModInt mi3) { - return new ModInt(ma.mul(value, mi1.value)).mulAsg(mi2).mulAsg(mi3); - } - public ModInt mul(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { - return new ModInt(ma.mul(value, mi1.value)).mulAsg(mi2).mulAsg(mi3).mulAsg(mi4); - } - public ModInt mul(ModInt mi1, ModInt... mis) { - ModInt mi = mul(mi1); - for (ModInt m : mis) mi.mulAsg(m); - return mi; - } - public ModInt mul(long mi) { - return new ModInt(ma.mul(value, ma.remainder(mi))); - } - public ModInt div(ModInt mi) { - return new ModInt(ma.div(value, mi.value)); - } - public ModInt div(long mi) { - return new ModInt(ma.div(value, ma.remainder(mi))); - } - public ModInt inv() { - return new ModInt(ma.inv(value)); - } - public ModInt pow(long b) { - return new ModInt(ma.pow(value, b)); - } - public ModInt addAsg(ModInt mi) { - this.value = ma.add(value, mi.value); - return this; - } - public ModInt addAsg(ModInt mi1, ModInt mi2) { - return addAsg(mi1).addAsg(mi2); - } - public ModInt addAsg(ModInt mi1, ModInt mi2, ModInt mi3) { - return addAsg(mi1).addAsg(mi2).addAsg(mi3); - } - public ModInt addAsg(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { - return addAsg(mi1).addAsg(mi2).addAsg(mi3).addAsg(mi4); - } - public ModInt addAsg(ModInt... mis) { - for (ModInt m : mis) addAsg(m); - return this; - } - public ModInt addAsg(long mi) { - this.value = ma.add(value, ma.remainder(mi)); - return this; - } - public ModInt subAsg(ModInt mi) { - this.value = ma.sub(value, mi.value); - return this; - } - public ModInt subAsg(long mi) { - this.value = ma.sub(value, ma.remainder(mi)); - return this; - } - public ModInt mulAsg(ModInt mi) { - this.value = ma.mul(value, mi.value); - return this; - } - public ModInt mulAsg(ModInt mi1, ModInt mi2) { - return mulAsg(mi1).mulAsg(mi2); - } - public ModInt mulAsg(ModInt mi1, ModInt mi2, ModInt mi3) { - return mulAsg(mi1).mulAsg(mi2).mulAsg(mi3); - } - public ModInt mulAsg(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { - return mulAsg(mi1).mulAsg(mi2).mulAsg(mi3).mulAsg(mi4); - } - public ModInt mulAsg(ModInt... mis) { - for (ModInt m : mis) mulAsg(m); - return this; - } - public ModInt mulAsg(long mi) { - this.value = ma.mul(value, ma.remainder(mi)); - return this; - } - public ModInt divAsg(ModInt mi) { - this.value = ma.div(value, mi.value); - return this; - } - public ModInt divAsg(long mi) { - this.value = ma.div(value, ma.remainder(mi)); - return this; - } - @Override - public String toString() { - return String.valueOf(value()); - } - @Override - public boolean equals(Object o) { - if (o instanceof ModInt) { - ModInt mi = (ModInt) o; - return mod() == mi.mod() && value() == mi.value(); - } - return false; - } - @Override - public int hashCode() { - return (1 * 37 + mod()) * 37 + value(); - } - } - - private interface ModArithmetic { - public int mod(); - public int remainder(long value); - public int add(int a, int b); - public int sub(int a, int b); - public int mul(int a, int b); - public default int div(int a, int b) { - return mul(a, inv(b)); - } - public int inv(int a); - public int pow(int a, long b); - - public static ModArithmetic of(int mod) { - if (mod <= 0) { - throw new IllegalArgumentException(); - } else if (mod == 1) { - return new ModArithmetic1(); - } else if (mod == 2) { - return new ModArithmetic2(); - } else if (mod == 998244353) { - return new ModArithmetic998244353(); - } else if (mod == 1000000007) { - return new ModArithmetic1000000007(); - } else if ((mod & 1) == 1) { - return new ModArithmeticMontgomery(mod); - } else { - return new ModArithmeticBarrett(mod); - } - } - - static final class ModArithmetic1 implements ModArithmetic { - public int mod() {return 1;} - public int remainder(long value) {return 0;} - public int add(int a, int b) {return 0;} - public int sub(int a, int b) {return 0;} - public int mul(int a, int b) {return 0;} - public int inv(int a) {throw new ArithmeticException("divide by zero");} - public int pow(int a, long b) {return 0;} - } - static final class ModArithmetic2 implements ModArithmetic { - public int mod() {return 2;} - public int remainder(long value) {return (int) (value & 1);} - public int add(int a, int b) {return a ^ b;} - public int sub(int a, int b) {return a ^ b;} - public int mul(int a, int b) {return a & b;} - public int inv(int a) { - if (a == 0) throw new ArithmeticException("divide by zero"); - return a; - } - public int pow(int a, long b) { - if (b == 0) return 1; - return a; - } - } - static final class ModArithmetic998244353 implements ModArithmetic { - private final int mod = 998244353; - public int mod() { - return mod; - } - public int remainder(long value) { - return (int) ((value %= mod) < 0 ? value + mod : value); - } - public int add(int a, int b) { - int res = a + b; - return res >= mod ? res - mod : res; - } - public int sub(int a, int b) { - int res = a - b; - return res < 0 ? res + mod : res; - } - public int mul(int a, int b) { - return (int) (((long) a * b) % mod); - } - public int inv(int a) { - int b = mod; - long u = 1, v = 0; - while (b >= 1) { - long t = a / b; - a -= t * b; - int tmp1 = a; a = b; b = tmp1; - u -= t * v; - long tmp2 = u; u = v; v = tmp2; - } - u %= mod; - if (a != 1) { - throw new ArithmeticException("divide by zero"); - } - return (int) (u < 0 ? u + mod : u); - } - public int pow(int a, long b) { - if (b < 0) throw new ArithmeticException("negative power"); - long res = 1; - long pow2 = a; - long idx = 1; - while (b > 0) { - long lsb = b & -b; - for (; lsb != idx; idx <<= 1) { - pow2 = (pow2 * pow2) % mod; - } - res = (res * pow2) % mod; - b ^= lsb; - } - return (int) res; - } - } - static final class ModArithmetic1000000007 implements ModArithmetic { - private final int mod = 1000000007; - public int mod() { - return mod; - } - public int remainder(long value) { - return (int) ((value %= mod) < 0 ? value + mod : value); - } - public int add(int a, int b) { - int res = a + b; - return res >= mod ? res - mod : res; - } - public int sub(int a, int b) { - int res = a - b; - return res < 0 ? res + mod : res; - } - public int mul(int a, int b) { - return (int) (((long) a * b) % mod); - } - public int div(int a, int b) { - return mul(a, inv(b)); - } - public int inv(int a) { - int b = mod; - long u = 1, v = 0; - while (b >= 1) { - long t = a / b; - a -= t * b; - int tmp1 = a; a = b; b = tmp1; - u -= t * v; - long tmp2 = u; u = v; v = tmp2; - } - u %= mod; - if (a != 1) { - throw new ArithmeticException("divide by zero"); - } - return (int) (u < 0 ? u + mod : u); - } - public int pow(int a, long b) { - if (b < 0) throw new ArithmeticException("negative power"); - long res = 1; - long pow2 = a; - long idx = 1; - while (b > 0) { - long lsb = b & -b; - for (; lsb != idx; idx <<= 1) { - pow2 = (pow2 * pow2) % mod; - } - res = (res * pow2) % mod; - b ^= lsb; - } - return (int) res; - } - } - static final class ModArithmeticMontgomery extends ModArithmeticDynamic { - private final long negInv; - private final long r2, r3; - - private ModArithmeticMontgomery(int mod) { - super(mod); - long inv = 0; - long s = 1, t = 0; - for (int i = 0; i < 32; i++) { - if ((t & 1) == 0) { - t += mod; - inv += s; - } - t >>= 1; - s <<= 1; - } - long r = (1l << 32) % mod; - this.negInv = inv; - this.r2 = (r * r) % mod; - this.r3 = (r2 * r) % mod; - } - private int generate(long x) { - return reduce(x * r2); - } - private int reduce(long x) { - x = (x + ((x * negInv) & 0xffff_ffffl) * mod) >>> 32; - return (int) (x < mod ? x : x - mod); - } - @Override - public int remainder(long value) { - return generate((value %= mod) < 0 ? value + mod : value); - } - @Override - public int mul(int a, int b) { - return reduce((long) a * b); - } - @Override - public int inv(int a) { - a = super.inv(a); - return reduce(a * r3); - } - @Override - public int pow(int a, long b) { - return generate(super.pow(a, b)); - } - } - static final class ModArithmeticBarrett extends ModArithmeticDynamic { - private static final long mask = 0xffff_ffffl; - private final long mh; - private final long ml; - private ModArithmeticBarrett(int mod) { - super(mod); - /** - * m = floor(2^64/mod) - * 2^64 = p*mod + q, 2^32 = a*mod + b - * => (a*mod + b)^2 = p*mod + q - * => p = mod*a^2 + 2ab + floor(b^2/mod) - */ - long a = (1l << 32) / mod; - long b = (1l << 32) % mod; - long m = a * a * mod + 2 * a * b + (b * b) / mod; - mh = m >>> 32; - ml = m & mask; - } - private int reduce(long x) { - long z = (x & mask) * ml; - z = (x & mask) * mh + (x >>> 32) * ml + (z >>> 32); - z = (x >>> 32) * mh + (z >>> 32); - x -= z * mod; - return (int) (x < mod ? x : x - mod); - } - @Override - public int remainder(long value) { - return (int) ((value %= mod) < 0 ? value + mod : value); - } - @Override - public int mul(int a, int b) { - return reduce((long) a * b); - } - } - static class ModArithmeticDynamic implements ModArithmetic { - final int mod; - public ModArithmeticDynamic(int mod) { - this.mod = mod; - } - public int mod() { - return mod; - } - public int remainder(long value) { - return (int) ((value %= mod) < 0 ? value + mod : value); - } - public int add(int a, int b) { - int sum = a + b; - return sum >= mod ? sum - mod : sum; - } - public int sub(int a, int b) { - int sum = a - b; - return sum < 0 ? sum + mod : sum; - } - public int mul(int a, int b) { - return (int) (((long) a * b) % mod); - } - public int inv(int a) { - int b = mod; - long u = 1, v = 0; - while (b >= 1) { - long t = a / b; - a -= t * b; - int tmp1 = a; a = b; b = tmp1; - u -= t * v; - long tmp2 = u; u = v; v = tmp2; - } - u %= mod; - if (a != 1) { - throw new ArithmeticException("divide by zero"); - } - return (int) (u < 0 ? u + mod : u); - } - public int pow(int a, long b) { - if (b < 0) throw new ArithmeticException("negative power"); - int res = 1; - int pow2 = a; - long idx = 1; - while (b > 0) { - long lsb = b & -b; - for (; lsb != idx; idx <<= 1) { - pow2 = mul(pow2, pow2); - } - res = mul(res, pow2); - b ^= lsb; - } - return res; - } - } - } +/** + * @verified + *
    + *
  • https://atcoder.jp/contests/arc050/tasks/arc050_c
  • + *
  • https://atcoder.jp/contests/abc129/tasks/abc129_f
  • + *
  • https://atcoder.jp/contests/arc012/tasks/arc012_4
  • + *
+ */ +class ModIntFactory { + private final ModArithmetic ma; + private final int mod; + + private final boolean usesMontgomery; + private final ModArithmetic.ModArithmeticMontgomery maMontgomery; + + public ModIntFactory(int mod) { + this.ma = ModArithmetic.of(mod); + this.usesMontgomery = ma instanceof ModArithmetic.ModArithmeticMontgomery; + this.maMontgomery = usesMontgomery ? (ModArithmetic.ModArithmeticMontgomery) ma : null; + this.mod = mod; + } + + public ModInt create(long value) { + if ((value %= mod) < 0) value += mod; + if (usesMontgomery) { + return new ModInt(maMontgomery.generate(value)); + } else { + return new ModInt((int) value); + } + } + + public int getMod() { + return mod; + } + + public class ModInt { + private int value; + private ModInt(int value) { + this.value = value; + } + public int mod() { + return mod; + } + public int value() { + if (ma instanceof ModArithmetic.ModArithmeticMontgomery) { + return ((ModArithmetic.ModArithmeticMontgomery) ma).reduce(value); + } + return value; + } + public ModInt add(ModInt mi) { + return new ModInt(ma.add(value, mi.value)); + } + public ModInt add(ModInt mi1, ModInt mi2) { + return new ModInt(ma.add(value, mi1.value)).addAsg(mi2); + } + public ModInt add(ModInt mi1, ModInt mi2, ModInt mi3) { + return new ModInt(ma.add(value, mi1.value)).addAsg(mi2).addAsg(mi3); + } + public ModInt add(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { + return new ModInt(ma.add(value, mi1.value)).addAsg(mi2).addAsg(mi3).addAsg(mi4); + } + public ModInt add(ModInt mi1, ModInt... mis) { + ModInt mi = add(mi1); + for (ModInt m : mis) mi.addAsg(m); + return mi; + } + public ModInt add(long mi) { + return new ModInt(ma.add(value, ma.remainder(mi))); + } + public ModInt sub(ModInt mi) { + return new ModInt(ma.sub(value, mi.value)); + } + public ModInt sub(long mi) { + return new ModInt(ma.sub(value, ma.remainder(mi))); + } + public ModInt mul(ModInt mi) { + return new ModInt(ma.mul(value, mi.value)); + } + public ModInt mul(ModInt mi1, ModInt mi2) { + return new ModInt(ma.mul(value, mi1.value)).mulAsg(mi2); + } + public ModInt mul(ModInt mi1, ModInt mi2, ModInt mi3) { + return new ModInt(ma.mul(value, mi1.value)).mulAsg(mi2).mulAsg(mi3); + } + public ModInt mul(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { + return new ModInt(ma.mul(value, mi1.value)).mulAsg(mi2).mulAsg(mi3).mulAsg(mi4); + } + public ModInt mul(ModInt mi1, ModInt... mis) { + ModInt mi = mul(mi1); + for (ModInt m : mis) mi.mulAsg(m); + return mi; + } + public ModInt mul(long mi) { + return new ModInt(ma.mul(value, ma.remainder(mi))); + } + public ModInt div(ModInt mi) { + return new ModInt(ma.div(value, mi.value)); + } + public ModInt div(long mi) { + return new ModInt(ma.div(value, ma.remainder(mi))); + } + public ModInt inv() { + return new ModInt(ma.inv(value)); + } + public ModInt pow(long b) { + return new ModInt(ma.pow(value, b)); + } + public ModInt addAsg(ModInt mi) { + this.value = ma.add(value, mi.value); + return this; + } + public ModInt addAsg(ModInt mi1, ModInt mi2) { + return addAsg(mi1).addAsg(mi2); + } + public ModInt addAsg(ModInt mi1, ModInt mi2, ModInt mi3) { + return addAsg(mi1).addAsg(mi2).addAsg(mi3); + } + public ModInt addAsg(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { + return addAsg(mi1).addAsg(mi2).addAsg(mi3).addAsg(mi4); + } + public ModInt addAsg(ModInt... mis) { + for (ModInt m : mis) addAsg(m); + return this; + } + public ModInt addAsg(long mi) { + this.value = ma.add(value, ma.remainder(mi)); + return this; + } + public ModInt subAsg(ModInt mi) { + this.value = ma.sub(value, mi.value); + return this; + } + public ModInt subAsg(long mi) { + this.value = ma.sub(value, ma.remainder(mi)); + return this; + } + public ModInt mulAsg(ModInt mi) { + this.value = ma.mul(value, mi.value); + return this; + } + public ModInt mulAsg(ModInt mi1, ModInt mi2) { + return mulAsg(mi1).mulAsg(mi2); + } + public ModInt mulAsg(ModInt mi1, ModInt mi2, ModInt mi3) { + return mulAsg(mi1).mulAsg(mi2).mulAsg(mi3); + } + public ModInt mulAsg(ModInt mi1, ModInt mi2, ModInt mi3, ModInt mi4) { + return mulAsg(mi1).mulAsg(mi2).mulAsg(mi3).mulAsg(mi4); + } + public ModInt mulAsg(ModInt... mis) { + for (ModInt m : mis) mulAsg(m); + return this; + } + public ModInt mulAsg(long mi) { + this.value = ma.mul(value, ma.remainder(mi)); + return this; + } + public ModInt divAsg(ModInt mi) { + this.value = ma.div(value, mi.value); + return this; + } + public ModInt divAsg(long mi) { + this.value = ma.div(value, ma.remainder(mi)); + return this; + } + @Override + public String toString() { + return String.valueOf(value()); + } + @Override + public boolean equals(Object o) { + if (o instanceof ModInt) { + ModInt mi = (ModInt) o; + return mod() == mi.mod() && value() == mi.value(); + } + return false; + } + @Override + public int hashCode() { + return (1 * 37 + mod()) * 37 + value(); + } + } + + private static abstract class ModArithmetic { + abstract int mod(); + abstract int remainder(long value); + abstract int add(int a, int b); + abstract int sub(int a, int b); + abstract int mul(int a, int b); + int div(int a, int b) { + return mul(a, inv(b)); + } + int inv(int a) { + int b = mod(); + long u = 1, v = 0; + while (b >= 1) { + int t = a / b; + a -= t * b; + int tmp1 = a; a = b; b = tmp1; + u -= t * v; + long tmp2 = u; u = v; v = tmp2; + } + if (a != 1) { + throw new ArithmeticException("divide by zero"); + } + return remainder(u); + } + int pow(int a, long b) { + if (b < 0) throw new ArithmeticException("negative power"); + int r = 1; + int x = a; + while (b > 0) { + if ((b & 1) == 1) r = mul(r, x); + x = mul(x, x); + b >>= 1; + } + return r; + } + + static ModArithmetic of(int mod) { + if (mod <= 0) { + throw new IllegalArgumentException(); + } else if (mod == 1) { + return new ModArithmetic1(); + } else if (mod == 2) { + return new ModArithmetic2(); + } else if (mod == 998244353) { + return new ModArithmetic998244353(); + } else if (mod == 1000000007) { + return new ModArithmetic1000000007(); + } else if ((mod & 1) == 1) { + return new ModArithmeticMontgomery(mod); + } else { + return new ModArithmeticBarrett(mod); + } + } + + private static final class ModArithmetic1 extends ModArithmetic { + int mod() {return 1;} + int remainder(long value) {return 0;} + int add(int a, int b) {return 0;} + int sub(int a, int b) {return 0;} + int mul(int a, int b) {return 0;} + int pow(int a, long b) {return 0;} + } + private static final class ModArithmetic2 extends ModArithmetic { + int mod() {return 2;} + int remainder(long value) {return (int) (value & 1);} + int add(int a, int b) {return a ^ b;} + int sub(int a, int b) {return a ^ b;} + int mul(int a, int b) {return a & b;} + } + private static final class ModArithmetic998244353 extends ModArithmetic { + private final int mod = 998244353; + int mod() { + return mod; + } + int remainder(long value) { + return (int) ((value %= mod) < 0 ? value + mod : value); + } + int add(int a, int b) { + int res = a + b; + return res >= mod ? res - mod : res; + } + int sub(int a, int b) { + int res = a - b; + return res < 0 ? res + mod : res; + } + int mul(int a, int b) { + return (int) (((long) a * b) % mod); + } + } + private static final class ModArithmetic1000000007 extends ModArithmetic { + private final int mod = 1000000007; + int mod() { + return mod; + } + int remainder(long value) { + return (int) ((value %= mod) < 0 ? value + mod : value); + } + int add(int a, int b) { + int res = a + b; + return res >= mod ? res - mod : res; + } + int sub(int a, int b) { + int res = a - b; + return res < 0 ? res + mod : res; + } + int mul(int a, int b) { + return (int) (((long) a * b) % mod); + } + } + private static final class ModArithmeticMontgomery extends ModArithmeticDynamic { + private final long negInv; + private final long r2; + + private ModArithmeticMontgomery(int mod) { + super(mod); + long inv = 0; + long s = 1, t = 0; + for (int i = 0; i < 32; i++) { + if ((t & 1) == 0) { + t += mod; + inv += s; + } + t >>= 1; + s <<= 1; + } + long r = (1l << 32) % mod; + this.negInv = inv; + this.r2 = (r * r) % mod; + } + private int generate(long x) { + return reduce(x * r2); + } + private int reduce(long x) { + x = (x + ((x * negInv) & 0xffff_ffffl) * mod) >>> 32; + return (int) (x < mod ? x : x - mod); + } + @Override + int remainder(long value) { + return generate((value %= mod) < 0 ? value + mod : value); + } + @Override + int mul(int a, int b) { + return reduce((long) a * b); + } + @Override + int inv(int a) { + return super.inv(reduce(a)); + } + @Override + int pow(int a, long b) { + return generate(super.pow(a, b)); + } + } + private static final class ModArithmeticBarrett extends ModArithmeticDynamic { + private static final long mask = 0xffff_ffffl; + private final long mh; + private final long ml; + private ModArithmeticBarrett(int mod) { + super(mod); + /** + * m = floor(2^64/mod) + * 2^64 = p*mod + q, 2^32 = a*mod + b + * => (a*mod + b)^2 = p*mod + q + * => p = mod*a^2 + 2ab + floor(b^2/mod) + */ + long a = (1l << 32) / mod; + long b = (1l << 32) % mod; + long m = a * a * mod + 2 * a * b + (b * b) / mod; + mh = m >>> 32; + ml = m & mask; + } + private int reduce(long x) { + long z = (x & mask) * ml; + z = (x & mask) * mh + (x >>> 32) * ml + (z >>> 32); + z = (x >>> 32) * mh + (z >>> 32); + x -= z * mod; + return (int) (x < mod ? x : x - mod); + } + @Override + int remainder(long value) { + return (int) ((value %= mod) < 0 ? value + mod : value); + } + @Override + int mul(int a, int b) { + return reduce((long) a * b); + } + } + private static class ModArithmeticDynamic extends ModArithmetic { + final int mod; + ModArithmeticDynamic(int mod) { + this.mod = mod; + } + int mod() { + return mod; + } + int remainder(long value) { + return (int) ((value %= mod) < 0 ? value + mod : value); + } + int add(int a, int b) { + int sum = a + b; + return sum >= mod ? sum - mod : sum; + } + int sub(int a, int b) { + int sum = a - b; + return sum < 0 ? sum + mod : sum; + } + int mul(int a, int b) { + return (int) (((long) a * b) % mod); + } + } + } } \ No newline at end of file From 3f525b5b495ba9b0e86633b88554cf639244a2da Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Sun, 20 Dec 2020 18:17:04 +0900 Subject: [PATCH 24/48] ModInt: fix #57 --- ModInt/ModInt.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ModInt/ModInt.java b/ModInt/ModInt.java index 0536dde..2e7891e 100644 --- a/ModInt/ModInt.java +++ b/ModInt/ModInt.java @@ -1,9 +1,11 @@ /** * @verified *
    - *
  • https://atcoder.jp/contests/arc050/tasks/arc050_c
  • - *
  • https://atcoder.jp/contests/abc129/tasks/abc129_f
  • - *
  • https://atcoder.jp/contests/arc012/tasks/arc012_4
  • + *
  • https://atcoder.jp/contests/m-solutions2019/tasks/m_solutions2019_c : (M = 1000000007) + *
  • https://atcoder.jp/contests/abc172/tasks/abc172_e : (M = 1000000007) + *
  • https://atcoder.jp/contests/abc129/tasks/abc129_f : (2 <= M <= 1000000000) + *
  • https://atcoder.jp/contests/arc050/tasks/arc050_c : (2 <= M <= 1000000000) + *
  • https://atcoder.jp/contests/arc012/tasks/arc012_4 : (1 <= M <= 1000000007) *
*/ class ModIntFactory { @@ -192,6 +194,7 @@ int div(int a, int b) { } int inv(int a) { int b = mod(); + if (b == 1) return 0; long u = 1, v = 0; while (b >= 1) { int t = a / b; From e452602fb702d2a92f2247ed5b9fad30831c79aa Mon Sep 17 00:00:00 2001 From: NASU41 Date: Thu, 21 Jan 2021 23:15:02 +0900 Subject: [PATCH 25/48] implement std::pair --- Pair/Pair.java | 25 +++++++++++++++++++++++++ Pair/README.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Pair/Pair.java create mode 100644 Pair/README.md diff --git a/Pair/Pair.java b/Pair/Pair.java new file mode 100644 index 0000000..decc8c6 --- /dev/null +++ b/Pair/Pair.java @@ -0,0 +1,25 @@ +class Pair, T extends Comparable> implements Comparable>{ + S first; + T second; + + public Pair(S s, T t){ + first = s; + second = t; + } + public boolean equals(Object another){ + if(this==another) return true; + if(!(another instanceof Pair)) return false; + Pair otherPair = (Pair)another; + return this.first.equals(otherPair.first) && this.second.equals(otherPair.second); + } + public int compareTo(Pair another){ + if(this.second.compareTo(another.second) == 0) return this.first.compareTo(another.first); + else return this.second.compareTo(another.second); + } + public int hashCode(){ + return first.hashCode() * 10007 + second.hashCode(); + } + public String toString(){ + return String.format("(%s, %s)", first, second); + } +} diff --git a/Pair/README.md b/Pair/README.md new file mode 100644 index 0000000..61781e0 --- /dev/null +++ b/Pair/README.md @@ -0,0 +1,32 @@ +# クラス Permutation + +本機能は AtCoderLibrary ではなく C++標準ライブラリ `std::pair` の移植です. +2要素の組を表現するオブジェクト型です. + +## コンストラクタ + +### Pair, T extends Comparable> + +```java +public Pair(S s, T t) +``` +2要素 $s, t$ の組を作成します. + +## メソッド + +### equals + +```java +public boolean equals(Object another) +``` +この組がオブジェクト `another` と等しい時にtrueを返す関数です. +ここで, Pairどうしが等しいとは, 第一要素どうしが等しくかつ第二要素どうしが等しいことを指します. + + +### compareTo + +```java +public int compareTo(Pair another) +``` +このオブジェクトと指定されたオブジェクトの順序を比較します. +第一要素どうしが等しくない場合はその順序を, 等しい場合は第二要素どうしの順序を返します(いわゆる辞書順). \ No newline at end of file From dbad12f1aa521273b373ecdc8d3705463ac41e97 Mon Sep 17 00:00:00 2001 From: NASU41 Date: Thu, 21 Jan 2021 23:58:19 +0900 Subject: [PATCH 26/48] Modint.factorial / combination / permutation --- 2SAT/Readme.md | 8 ++++++++ 2SAT/TwoSAT.java | 4 ++++ Convolution/README.md | 2 +- DSU/README.md | 2 +- ModInt/ModInt.java | 33 +++++++++++++++++++++++++++++++++ ModInt/README.md | 18 ++++++++++++++++++ 6 files changed, 65 insertions(+), 2 deletions(-) diff --git a/2SAT/Readme.md b/2SAT/Readme.md index b59e2c3..df59919 100644 --- a/2SAT/Readme.md +++ b/2SAT/Readme.md @@ -71,6 +71,14 @@ public void addNand(int x, boolean f, int y, boolean g) ならし $O(1)$ +### set + +```java +public void set(int x, boolean f) +``` + +`(x[i] = f)` というクローズを足します。 + ### satisfiable ```java diff --git a/2SAT/TwoSAT.java b/2SAT/TwoSAT.java index 211bae2..48d05f9 100644 --- a/2SAT/TwoSAT.java +++ b/2SAT/TwoSAT.java @@ -29,6 +29,10 @@ public void addImplication(int x, boolean f, int y, boolean g) { public void addNand(int x, boolean f, int y, boolean g) { addClause(x, !f, y, !g); } + public void set(int x, boolean f){ + addClause(x, f, x, f); + } + public boolean satisfiable() { hasCalledSatisfiable = true; diff --git a/Convolution/README.md b/Convolution/README.md index ac3e741..df7ec2c 100644 --- a/Convolution/README.md +++ b/Convolution/README.md @@ -15,7 +15,7 @@ public static void main(String[] args) { int mod = 998244353; long[] a = { 1, 2, 3, 4, 5 }; long[] b = { 6, 7, 8 }; - // 畳み込みを計算しまqす。a.length + b.length - 1 の配列が帰ります。 + // 畳み込みを計算します。a.length + b.length - 1 の配列が帰ります。 long[] ret = Convolution.convolution(a, b, mod); System.out.println(Arrays.toString(ret)); } diff --git a/DSU/README.md b/DSU/README.md index 3d8ccdd..1517880 100644 --- a/DSU/README.md +++ b/DSU/README.md @@ -8,7 +8,7 @@ を $O(α(N))$ 時間で処理することが出来ます。 -また、内部的に各連結成分ごとに代表となる頂点を 11 つ持っています。辺の追加により連結成分がマージされる時、新たな代表元は元の連結成分の代表元のうちどちらかになります。 +また、内部的に各連結成分ごとに代表となる頂点を 1 つ持っています。辺の追加により連結成分がマージされる時、新たな代表元は元の連結成分の代表元のうちどちらかになります。 ## コンストラクタ ### DSU diff --git a/ModInt/ModInt.java b/ModInt/ModInt.java index 2e7891e..6409d7d 100644 --- a/ModInt/ModInt.java +++ b/ModInt/ModInt.java @@ -1,3 +1,7 @@ +import java.util.*; + +import java.util.ArrayList; + /** * @verified *
    @@ -6,6 +10,7 @@ *
  • https://atcoder.jp/contests/abc129/tasks/abc129_f : (2 <= M <= 1000000000) *
  • https://atcoder.jp/contests/arc050/tasks/arc050_c : (2 <= M <= 1000000000) *
  • https://atcoder.jp/contests/arc012/tasks/arc012_4 : (1 <= M <= 1000000007) + *
  • https://atcoder.jp/contests/abc042/tasks/arc058_b : (M = 1000000007, combination ver.) *
*/ class ModIntFactory { @@ -15,11 +20,15 @@ class ModIntFactory { private final boolean usesMontgomery; private final ModArithmetic.ModArithmeticMontgomery maMontgomery; + private ArrayList factorial; + public ModIntFactory(int mod) { this.ma = ModArithmetic.of(mod); this.usesMontgomery = ma instanceof ModArithmetic.ModArithmeticMontgomery; this.maMontgomery = usesMontgomery ? (ModArithmetic.ModArithmeticMontgomery) ma : null; this.mod = mod; + + this.factorial = new ArrayList<>(); } public ModInt create(long value) { @@ -31,6 +40,30 @@ public ModInt create(long value) { } } + private void prepareFactorial(int max){ + factorial.ensureCapacity(max+1); + if(factorial.size()==0) factorial.add(1); + for(int i=factorial.size(); i<=max; i++){ + factorial.add(ma.mul(factorial.get(i-1), i)); + } + } + + public ModInt factorial(int i){ + prepareFactorial(i); + return create(factorial.get(i)); + } + + public ModInt permutation(int n, int r){ + if(n < 0 || r < 0 || n < r) return create(0); + prepareFactorial(n); + return create(ma.div(factorial.get(n), factorial.get(r))); + } + public ModInt combination(int n, int r){ + if(n < 0 || r < 0 || n < r) return create(0); + prepareFactorial(n); + return create(ma.div(factorial.get(n), ma.mul(factorial.get(r),factorial.get(n-r)))); + } + public int getMod() { return mod; } diff --git a/ModInt/README.md b/ModInt/README.md index e2a6268..e9a5236 100644 --- a/ModInt/README.md +++ b/ModInt/README.md @@ -61,6 +61,24 @@ public ModInt create(long value) 値 `value % mod` を持つ `ModInt` を生成します. 計算量: $O(1)$ +```java +public ModInt factorial(int i) +``` + +値 `(i!) % mod` を持つ `ModInt` を生成します. + +```java +public ModInt permutation(int n, int r) +``` + +値 `n P r` を持つ `ModInt` を生成します. + +```java +public ModInt combination(int n, int r) +``` + +値 `n C r` を持つ `ModInt` を生成します. + ### ModIntFactory$ModInt #### mod From cadb741fca3afc5a11d71074e5fa8612e5e77fb9 Mon Sep 17 00:00:00 2001 From: NASU41 Date: Sat, 6 Feb 2021 23:28:07 +0900 Subject: [PATCH 27/48] MathLib.gcd/lcm/divisors --- Math/MathLib.java | 25 +++++++++++++++++++++++++ Math/README.md | 16 +++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Math/MathLib.java b/Math/MathLib.java index 2a5c054..5a309da 100644 --- a/Math/MathLib.java +++ b/Math/MathLib.java @@ -22,6 +22,17 @@ private static long[] inv_gcd(long a, long b){ return new long[]{s,m0}; } + public static long gcd(long a, long b){ + a = java.lang.Math.abs(a); + b = java.lang.Math.abs(b); + return inv_gcd(a, b)[0]; + } + public static long lcm(long a, long b){ + a = java.lang.Math.abs(a); + b = java.lang.Math.abs(b); + return a / gcd(a,b) * b; + } + public static long pow_mod(long x, long n, int m){ assert n >= 0; assert m >= 1; @@ -86,4 +97,18 @@ public static long floor_sum(long n, long m, long a, long b){ ans += floor_sum(y_max, a, m, (a-x_max%a)%a); return ans; } + + public static java.util.ArrayList divisors(long n){ + java.util.ArrayList divisors = new ArrayList<>(); + java.util.ArrayList large = new ArrayList<>(); + + for(long i=1; i*i<=n; i++) if(n%i==0){ + divisors.add(i); + if(i*i=0; p--){ + divisors.add(large.get(p)); + } + return divisors; + } } \ No newline at end of file diff --git a/Math/README.md b/Math/README.md index f2970b3..b227b3e 100644 --- a/Math/README.md +++ b/Math/README.md @@ -21,4 +21,18 @@ $$ x \equiv r[i] \mod m[i] $$ を解きます. public static long floor_sum(long n, long m, long a, long b) ``` -$ \sigma_{i=0}^{n-1} floor(\frac{a*i+b}{m}) $を返します. \ No newline at end of file +$ \sigma_{i=0}^{n-1} floor(\frac{a*i+b}{m}) $を返します. + +## gcd, lcm + +```java +public static long gcd(long a, long b) +public static long lcm(long a, long b) +``` +二整数 a, b の最大公約数/最小公倍数を返します. 返り値は必ず非負整数になります. + +```java +public static java.util.ArrayList divisors(int n) +``` +整数nの約数を昇順に含んだリストを返します. +計算量: O(√n) \ No newline at end of file From 01034808085e31e511c72f9267e8dc0f9f8242c5 Mon Sep 17 00:00:00 2001 From: NASU41 Date: Fri, 19 Feb 2021 16:29:00 +0900 Subject: [PATCH 28/48] add FastIO --- ContestIO/ContestPrinter.java | 92 +++++++++++++++++++++ ContestIO/ContestScanner.java | 146 ++++++++++++++++++++++++++++++++++ ContestIO/README.md | 124 +++++++++++++++++++++++++++++ README.md | 1 + 4 files changed, 363 insertions(+) create mode 100644 ContestIO/ContestPrinter.java create mode 100644 ContestIO/ContestScanner.java create mode 100644 ContestIO/README.md diff --git a/ContestIO/ContestPrinter.java b/ContestIO/ContestPrinter.java new file mode 100644 index 0000000..49eb259 --- /dev/null +++ b/ContestIO/ContestPrinter.java @@ -0,0 +1,92 @@ +class ContestPrinter extends java.io.PrintWriter{ + public ContestPrinter(java.io.PrintStream stream){ + super(stream); + } + public ContestPrinter(){ + super(System.out); + } + + private static String dtos(double x, int n) { + StringBuilder sb = new StringBuilder(); + if(x < 0){ + sb.append('-'); + x = -x; + } + x += Math.pow(10, -n)/2; + sb.append((long)x); + sb.append("."); + x -= (long)x; + for(int i = 0;i < n;i++){ + x *= 10; + sb.append((int)x); + x -= (int)x; + } + return sb.toString(); + } + + @Override + public void print(float f){ + super.print(dtos(f, 20)); + } + @Override + public void println(float f){ + super.println(dtos(f, 20)); + } + @Override + public void print(double d){ + super.print(dtos(d, 20)); + } + @Override + public void println(double d){ + super.println(dtos(d, 20)); + } + + + + public void printArray(int[] array, String separator){ + int n = array.length; + for(int i=0; i Integer.MAX_VALUE) throw new NumberFormatException(); + return (int) nl; + } + public double nextDouble() { + return Double.parseDouble(next()); + } + + public long[] nextLongArray(int length){ + long[] array = new long[length]; + for(int i=0; i Date: Tue, 9 Mar 2021 23:12:30 +0900 Subject: [PATCH 29/48] fix #59 --- ContestIO/ContestScanner.java | 56 ++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/ContestIO/ContestScanner.java b/ContestIO/ContestScanner.java index b260102..816fc4e 100644 --- a/ContestIO/ContestScanner.java +++ b/ContestIO/ContestScanner.java @@ -1,8 +1,16 @@ -class ContestScanner{ +import java.io.IOException; +import java.io.UncheckedIOException; + +class ContestScanner implements AutoCloseable { private final java.io.InputStream in; private final byte[] buffer = new byte[1024]; private int ptr = 0; private int buflen = 0; + + private static final long LONG_MAX_TENTHS = 922337203685477580L; + private static final int LONG_MAX_LAST_DIGIT = 7; + private static final int LONG_MIN_LAST_DIGIT = 8; + public ContestScanner(java.io.InputStream in){ this.in = in; } @@ -59,10 +67,42 @@ public long nextLong() { if (b < '0' || '9' < b) { throw new NumberFormatException(); } - while(true){ + while (true) { if ('0' <= b && b <= '9') { - n *= 10; - n += b - '0'; + int digit = b - '0'; + if (n >= LONG_MAX_TENTHS) { + if (n == LONG_MAX_TENTHS) { + if (minus) { + if (digit <= LONG_MIN_LAST_DIGIT) { + n = -n * 10 - digit; + b = readByte(); + if (!isPrintableChar(b)) { + return n; + } else if (b < '0' || '9' < b) { + throw new NumberFormatException( + String.format("%d%s... is not number", n, Character.toString(b)) + ); + } + } + } else { + if (digit <= LONG_MAX_LAST_DIGIT) { + n = n * 10 + digit; + b = readByte(); + if (!isPrintableChar(b)) { + return n; + } else if (b < '0' || '9' < b) { + throw new NumberFormatException( + String.format("%d%s... is not number", n, Character.toString(b)) + ); + } + } + } + } + throw new ArithmeticException( + String.format("%s%d%d... overflows long.", minus ? "-" : "", n, digit) + ); + } + n = n * 10 + digit; }else if(b == -1 || !isPrintableChar(b)){ return minus ? -n : n; }else{ @@ -143,4 +183,12 @@ public char[][] nextCharMatrix(int height, int width){ } return mat; } + @Override + public void close() { + try { + in.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } } \ No newline at end of file From 69adbaaa5b15f8ac48407eed2e1f2d21f5b9ed98 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Tue, 9 Mar 2021 23:13:52 +0900 Subject: [PATCH 30/48] fix #59 --- ContestIO/ContestScanner.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ContestIO/ContestScanner.java b/ContestIO/ContestScanner.java index 816fc4e..2878ec6 100644 --- a/ContestIO/ContestScanner.java +++ b/ContestIO/ContestScanner.java @@ -1,7 +1,4 @@ -import java.io.IOException; -import java.io.UncheckedIOException; - -class ContestScanner implements AutoCloseable { +class ContestScanner { private final java.io.InputStream in; private final byte[] buffer = new byte[1024]; private int ptr = 0; @@ -183,12 +180,4 @@ public char[][] nextCharMatrix(int height, int width){ } return mat; } - @Override - public void close() { - try { - in.close(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } } \ No newline at end of file From 6dbe977775edb8da07a62ffb8b1696dafd55ad40 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Wed, 10 Mar 2021 15:46:43 +0900 Subject: [PATCH 31/48] self-loop handling --- MaxFlow/Main.java | 108 +++++++++++++++++++++ MaxFlow/MaxFlow.java | 202 ++++++++++++++++++--------------------- MaxFlow/MaxFlowTest.java | 150 +++++++++++++++++++++++++++++ 3 files changed, 350 insertions(+), 110 deletions(-) create mode 100644 MaxFlow/Main.java create mode 100644 MaxFlow/MaxFlowTest.java diff --git a/MaxFlow/Main.java b/MaxFlow/Main.java new file mode 100644 index 0000000..b39ba52 --- /dev/null +++ b/MaxFlow/Main.java @@ -0,0 +1,108 @@ +import java.util.Arrays; +import java.util.Scanner; + +/** + * @problem + * AtCoder Library Practice Contest D - Maxflow + * {@link https://atcoder.jp/contests/practice2/tasks/practice2_d} + * @submission + * {@link https://atcoder.jp/contests/practice2/submissions/20808482} + */ +public class Main { + static class Answer { + final int c; + final char[][] g; + Answer(int c, char[][] g) { this.c = c; this.g = g; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(c); + for (char[] row : g) { + sb.append('\n').append(row); + } + return sb.toString(); + } + } + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = Integer.parseInt(sc.next()); + int m = Integer.parseInt(sc.next()); + char[][] g = new char[n][]; + Arrays.setAll(g, i -> sc.next().toCharArray()); + sc.close(); + System.out.println(solve(n, m, g)); + } + + public static Answer solve(int n, int m, char[][] g) { + MaxFlow mf = new MaxFlow(n * m + 2); + int s = n * m; + int t = s + 1; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (g[i][j] == '#') continue; + if (((i ^ j) & 1) == 0) { + mf.addEdge(s, i * m + j, 1); + } else { + mf.addEdge(i * m + j, t, 1); + } + } + } + for (int i = 0; i < n; i++) { + for (int j = i & 1; j < m; j += 2) { + if (g[i][j] == '#') continue; + if (j - 1 >= 0 && g[i][j - 1] == '.') { + mf.addEdge(i * m + j, i * m + (j - 1), 1); + } + if (j + 1 < m && g[i][j + 1] == '.') { + mf.addEdge(i * m + j, i * m + (j + 1), 1); + } + if (i - 1 >= 0 && g[i - 1][j] == '.') { + mf.addEdge(i * m + j, (i - 1) * m + j, 1); + } + if (i + 1 < n && g[i + 1][j] == '.') { + mf.addEdge(i * m + j, (i + 1) * m + j, 1); + } + } + } + int ans = (int) mf.maxFlow(s, t); + int cnt = 0; + for (var e : mf.getEdges()) { + if (e.flow == 0) continue; + int u = e.from; + int v = e.to; + if (u == s || v == t) continue; + int ui = u / m, uj = u % m; + int vi = v / m, vj = v % m; + if (g[ui][uj] != '.' || g[vi][vj] != '.') { + throw new AssertionError(); + } + if (ui == vi) { + if (uj + 1 == vj) { + g[ui][uj] = '>'; + g[vi][vj] = '<'; + } else if (uj == vj + 1) { + g[ui][uj] = '<'; + g[vi][vj] = '>'; + } else { + throw new AssertionError(); + } + } else if (uj == vj) { + if (ui + 1 == vi) { + g[ui][uj] = 'v'; + g[vi][vj] = '^'; + } else if (ui == vi + 1) { + g[ui][uj] = '^'; + g[vi][vj] = 'v'; + } else { + throw new AssertionError(); + } + } else { + throw new AssertionError(); + } + cnt++; + } + if (ans != cnt) throw new AssertionError(); + return new Answer(ans, g); + } +} + diff --git a/MaxFlow/MaxFlow.java b/MaxFlow/MaxFlow.java index 8994419..3995c07 100644 --- a/MaxFlow/MaxFlow.java +++ b/MaxFlow/MaxFlow.java @@ -1,80 +1,93 @@ -/** - * @verified https://atcoder.jp/contests/practice2/tasks/practice2_d - */ class MaxFlow { - public class CapEdge { - private final int from, to; - private long cap; - private final int rev; - CapEdge(int from, int to, long cap, int rev) { - this.from = from; - this.to = to; - this.cap = cap; - this.rev = rev; + private static final class InternalCapEdge { + final int to; + final int rev; + long cap; + InternalCapEdge(int to, int rev, long cap) { this.to = to; this.rev = rev; this.cap = cap; } + } + public static final class CapEdge { + final int from, to; + final long cap, flow; + CapEdge(int from, int to, long cap, long flow) { this.from = from; this.to = to; this.cap = cap; this.flow = flow; } + @Override + public boolean equals(Object o) { + if (o instanceof CapEdge) { + CapEdge e = (CapEdge) o; + return from == e.from && to == e.to && cap == e.cap && flow == e.flow; + } + return false; } - public int getFrom() {return from;} - public int getTo() {return to;} - public long getCap() {return cap;} - public long getFlow() {return g[to][rev].cap;} + } + private static final class IntPair { + final int first, second; + IntPair(int first, int second) { this.first = first; this.second = second; } } - private static final long INF = Long.MAX_VALUE; + static final long INF = Long.MAX_VALUE; private final int n; - private int m; - private final java.util.ArrayList edges; - private final int[] count; - private final CapEdge[][] g; + private final java.util.ArrayList pos; + private final java.util.ArrayList[] g; + @SuppressWarnings("unchecked") public MaxFlow(int n) { this.n = n; - this.edges = new java.util.ArrayList<>(); - this.count = new int[n]; - this.g = new CapEdge[n][]; + this.pos = new java.util.ArrayList<>(); + this.g = new java.util.ArrayList[n]; + for (int i = 0; i < n; i++) { + this.g[i] = new java.util.ArrayList<>(); + } } public int addEdge(int from, int to, long cap) { rangeCheck(from, 0, n); rangeCheck(to, 0, n); nonNegativeCheck(cap, "Capacity"); - CapEdge e = new CapEdge(from, to, cap, count[to]); - count[from]++; count[to]++; - edges.add(e); - return m++; + int m = pos.size(); + pos.add(new IntPair(from, g[from].size())); + int fromId = g[from].size(); + int toId = g[to].size(); + if (from == to) toId++; + g[from].add(new InternalCapEdge(to, toId, cap)); + g[to].add(new InternalCapEdge(from, fromId, 0L)); + return m; + } + + private InternalCapEdge getInternalEdge(int i) { + return g[pos.get(i).first].get(pos.get(i).second); + } + + private InternalCapEdge getInternalEdgeReversed(InternalCapEdge e) { + return g[e.to].get(e.rev); } public CapEdge getEdge(int i) { + int m = pos.size(); rangeCheck(i, 0, m); - return edges.get(i); + InternalCapEdge e = getInternalEdge(i); + InternalCapEdge re = getInternalEdgeReversed(e); + return new CapEdge(re.to, e.to, e.cap + re.cap, re.cap); } - public java.util.ArrayList getEdges() { - return edges; + public CapEdge[] getEdges() { + CapEdge[] res = new CapEdge[pos.size()]; + java.util.Arrays.setAll(res, this::getEdge); + return res; } public void changeEdge(int i, long newCap, long newFlow) { + int m = pos.size(); rangeCheck(i, 0, m); nonNegativeCheck(newCap, "Capacity"); if (newFlow > newCap) { throw new IllegalArgumentException( - String.format("Flow %d is greater than capacity %d.", newCap, newFlow) + String.format("Flow %d is greater than the capacity %d.", newCap, newFlow) ); } - CapEdge e = edges.get(i); - CapEdge er = g[e.to][e.rev]; + InternalCapEdge e = getInternalEdge(i); + InternalCapEdge re = getInternalEdgeReversed(e); e.cap = newCap - newFlow; - er.cap = newFlow; - } - - private void buildGraph() { - for (int i = 0; i < n; i++) { - g[i] = new CapEdge[count[i]]; - } - int[] idx = new int[n]; - for (CapEdge e : edges) { - g[e.to][idx[e.to]++] = new CapEdge(e.to, e.from, 0, idx[e.from]); - g[e.from][idx[e.from]++] = e; - } + re.cap = newFlow; } public long maxFlow(int s, int t) { @@ -84,34 +97,33 @@ public long maxFlow(int s, int t) { public long flow(int s, int t, long flowLimit) { rangeCheck(s, 0, n); rangeCheck(t, 0, n); - buildGraph(); - long flow = 0; + long flow = 0L; int[] level = new int[n]; int[] que = new int[n]; int[] iter = new int[n]; - while (true) { - java.util.Arrays.fill(level, -1); - dinicBFS(s, t, level, que); - if (level[t] < 0) return flow; + while (flow < flowLimit) { + bfs(s, t, level, que); + if (level[t] < 0) break; java.util.Arrays.fill(iter, 0); - while (true) { - long d = dinicDFS(t, s, flowLimit - flow, iter, level); - if (d <= 0) break; + while (flow < flowLimit) { + long d = dfs(t, s, flowLimit - flow, iter, level); + if (d == 0) break; flow += d; - if (flow == flowLimit) return flow; } } + return flow; } - private void dinicBFS(int s, int t, int[] level, int[] que) { + private void bfs(int s, int t, int[] level, int[] que) { + java.util.Arrays.fill(level, -1); int hd = 0, tl = 0; que[tl++] = s; level[s] = 0; - while (tl > hd) { + while (hd < tl) { int u = que[hd++]; - for (CapEdge e : g[u]) { + for (InternalCapEdge e : g[u]) { int v = e.to; - if (e.cap <= 0 || level[v] >= 0) continue; + if (e.cap == 0 || level[v] >= 0) continue; level[v] = level[u] + 1; if (v == t) return; que[tl++] = v; @@ -119,73 +131,43 @@ private void dinicBFS(int s, int t, int[] level, int[] que) { } } - private long dinicDFS(int cur, int s, long f, int[] iter, int[] level) { - if (cur == s) return f; + private long dfs(int cur, int s, long flowLimit, int[] iter, int[] level) { + if (cur == s) return flowLimit; long res = 0; - while (iter[cur] < count[cur]) { - CapEdge er = g[cur][iter[cur]++]; - int u = er.to; - CapEdge e = g[u][er.rev]; - if (level[u] >= level[cur] || e.cap <= 0) continue; - long d = dinicDFS(u, s, Math.min(f - res, e.cap), iter, level); + int curLevel = level[cur]; + for (int itMax = g[cur].size(); iter[cur] < itMax; iter[cur]++) { + int i = iter[cur]; + InternalCapEdge e = g[cur].get(i); + InternalCapEdge re = getInternalEdgeReversed(e); + if (curLevel <= level[e.to] || re.cap == 0) continue; + long d = dfs(e.to, s, Math.min(flowLimit - res, re.cap), iter, level); if (d <= 0) continue; - e.cap -= d; - er.cap += d; + e.cap += d; + re.cap -= d; res += d; - if (res == f) break; + if (res == flowLimit) break; } return res; } - public long fordFulkersonMaxFlow(int s, int t) { - return fordFulkersonFlow(s, t, INF); - } - - public long fordFulkersonFlow(int s, int t, long flowLimit) { - rangeCheck(s, 0, n); - rangeCheck(t, 0, n); - buildGraph(); - boolean[] used = new boolean[n]; - long flow = 0; - while (true) { - java.util.Arrays.fill(used, false); - long f = fordFulkersonDFS(s, t, flowLimit - flow, used); - if (f <= 0) return flow; - flow += f; - } - } - - private long fordFulkersonDFS(int cur, int t, long f, boolean[] used) { - if (cur == t) return f; - used[cur] = true; - for (CapEdge e : g[cur]) { - if (used[e.to] || e.cap <= 0) continue; - long d = fordFulkersonDFS(e.to, t, Math.min(f, e.cap), used); - if (d <= 0) continue; - e.cap -= d; - g[e.to][e.rev].cap += d; - return d; - } - return 0; - } - public boolean[] minCut(int s) { rangeCheck(s, 0, n); - boolean[] reachable = new boolean[n]; + boolean[] visited = new boolean[n]; int[] stack = new int[n]; int ptr = 0; stack[ptr++] = s; - reachable[s] = true; + visited[s] = true; while (ptr > 0) { int u = stack[--ptr]; - for (CapEdge e : g[u]) { + for (InternalCapEdge e : g[u]) { int v = e.to; - if (reachable[v] || e.cap <= 0) continue; - reachable[v] = true; - stack[ptr++] = v; + if (e.cap > 0 && !visited[v]) { + visited[v] = true; + stack[ptr++] = v; + } } } - return reachable; + return visited; } private void rangeCheck(int i, int minInclusive, int maxExclusive) { diff --git a/MaxFlow/MaxFlowTest.java b/MaxFlow/MaxFlowTest.java new file mode 100644 index 0000000..58d578c --- /dev/null +++ b/MaxFlow/MaxFlowTest.java @@ -0,0 +1,150 @@ +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.junit.Test; + +/** + * From: https://github.com/atcoder/ac-library/blob/1ca9100261b8c27cf62acccc3618c5e8375bf57b/test/unittest/maxflow_test.cpp + */ +public class MaxFlowTest { + @Test + public void simple() { + MaxFlow g = new MaxFlow(4); + assertEquals(0, g.addEdge(0, 1, 1)); + assertEquals(1, g.addEdge(0, 2, 1)); + assertEquals(2, g.addEdge(1, 3, 1)); + assertEquals(3, g.addEdge(2, 3, 1)); + assertEquals(4, g.addEdge(1, 2, 1)); + assertEquals(2, g.maxFlow(0, 3)); + + MaxFlow.CapEdge e; + e = new MaxFlow.CapEdge(0, 1, 1, 1); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(0, 2, 1, 1); + assertEquals(e, g.getEdge(1)); + e = new MaxFlow.CapEdge(1, 3, 1, 1); + assertEquals(e, g.getEdge(2)); + e = new MaxFlow.CapEdge(2, 3, 1, 1); + assertEquals(e, g.getEdge(3)); + e = new MaxFlow.CapEdge(1, 2, 1, 0); + assertEquals(e, g.getEdge(4)); + + assertTrue(Arrays.equals(new boolean[]{true, false, false, false}, g.minCut(0))); + } + + @Test + public void notSimple() { + MaxFlow g = new MaxFlow(2); + assertEquals(0, g.addEdge(0, 1, 1)); + assertEquals(1, g.addEdge(0, 1, 2)); + assertEquals(2, g.addEdge(0, 1, 3)); + assertEquals(3, g.addEdge(0, 1, 4)); + assertEquals(4, g.addEdge(0, 1, 5)); + assertEquals(5, g.addEdge(0, 0, 6)); + assertEquals(6, g.addEdge(1, 1, 7)); + assertEquals(15, g.maxFlow(0, 1)); + + MaxFlow.CapEdge e; + e = new MaxFlow.CapEdge(0, 1, 1, 1); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(0, 1, 2, 2); + assertEquals(e, g.getEdge(1)); + e = new MaxFlow.CapEdge(0, 1, 3, 3); + assertEquals(e, g.getEdge(2)); + e = new MaxFlow.CapEdge(0, 1, 4, 4); + assertEquals(e, g.getEdge(3)); + e = new MaxFlow.CapEdge(0, 1, 5, 5); + assertEquals(e, g.getEdge(4)); + + assertTrue(Arrays.equals(new boolean[]{true, false}, g.minCut(0))); + } + + @Test + public void cut() { + MaxFlow g = new MaxFlow(3); + assertEquals(0, g.addEdge(0, 1, 2)); + assertEquals(1, g.addEdge(1, 2, 1)); + assertEquals(1, g.maxFlow(0, 2)); + + MaxFlow.CapEdge e; + e = new MaxFlow.CapEdge(0, 1, 2, 1); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(1, 2, 1, 1); + assertEquals(e, g.getEdge(1)); + + assertTrue(Arrays.equals(new boolean[]{true, true, false}, g.minCut(0))); + } + + @Test + public void twise() { + MaxFlow.CapEdge e; + + MaxFlow g = new MaxFlow(3); + assertEquals(0, g.addEdge(0, 1, 1)); + assertEquals(1, g.addEdge(0, 2, 1)); + assertEquals(2, g.addEdge(1, 2, 1)); + + assertEquals(2, g.maxFlow(0, 2)); + + e = new MaxFlow.CapEdge(0, 1, 1, 1); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(0, 2, 1, 1); + assertEquals(e, g.getEdge(1)); + e = new MaxFlow.CapEdge(1, 2, 1, 1); + assertEquals(e, g.getEdge(2)); + + g.changeEdge(0, 100, 10); + e = new MaxFlow.CapEdge(0, 1, 100, 10); + assertEquals(e, g.getEdge(0)); + + assertEquals(0, g.maxFlow(0, 2)); + assertEquals(90, g.maxFlow(0, 1)); + + e = new MaxFlow.CapEdge(0, 1, 100, 100); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(0, 2, 1, 1); + assertEquals(e, g.getEdge(1)); + e = new MaxFlow.CapEdge(1, 2, 1, 1); + assertEquals(e, g.getEdge(2)); + + assertEquals(2, g.maxFlow(2, 0)); + + e = new MaxFlow.CapEdge(0, 1, 100, 99); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(0, 2, 1, 0); + assertEquals(e, g.getEdge(1)); + e = new MaxFlow.CapEdge(1, 2, 1, 0); + assertEquals(e, g.getEdge(2)); + } + + @Test + public void bound() { + MaxFlow.CapEdge e; + + long INF = MaxFlow.INF; + MaxFlow g = new MaxFlow(3); + assertEquals(0, g.addEdge(0, 1, INF)); + assertEquals(1, g.addEdge(1, 0, INF)); + assertEquals(2, g.addEdge(0, 2, INF)); + + assertEquals(INF, g.maxFlow(0, 2)); + + e = new MaxFlow.CapEdge(0, 1, INF, 0); + assertEquals(e, g.getEdge(0)); + e = new MaxFlow.CapEdge(1, 0, INF, 0); + assertEquals(e, g.getEdge(1)); + e = new MaxFlow.CapEdge(0, 2, INF, INF); + assertEquals(e, g.getEdge(2)); + } + + @Test + public void selfLoop() { + MaxFlow g = new MaxFlow(3); + assertEquals(0, g.addEdge(0, 0, 100)); + + MaxFlow.CapEdge e = new MaxFlow.CapEdge(0, 0, 100, 0); + assertEquals(e, g.getEdge(0)); + } +} \ No newline at end of file From 79ba007b1b8898480c0bba13ad20644f778b69f3 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Wed, 10 Mar 2021 19:27:09 +0900 Subject: [PATCH 32/48] add test for MaxFlow --- MaxFlow/Main.java | 201 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 173 insertions(+), 28 deletions(-) diff --git a/MaxFlow/Main.java b/MaxFlow/Main.java index b39ba52..5325bc0 100644 --- a/MaxFlow/Main.java +++ b/MaxFlow/Main.java @@ -1,39 +1,29 @@ import java.util.Arrays; import java.util.Scanner; +public class Main { + static Solver practice2_d = new practice2_d(); + static Solver arc074_d = new arc074_d(); + static Solver abc193_f = new abc193_f(); + + public static void main(String[] args) { + // practice2_d.run(); + // arc074_d.run(); + abc193_f.run(); + } +} + +abstract class Solver implements Runnable { public abstract void run(); } + /** * @problem * AtCoder Library Practice Contest D - Maxflow - * {@link https://atcoder.jp/contests/practice2/tasks/practice2_d} + * {@see https://atcoder.jp/contests/practice2/tasks/practice2_d} * @submission - * {@link https://atcoder.jp/contests/practice2/submissions/20808482} + * {@see https://atcoder.jp/contests/practice2/submissions/20808482} */ -public class Main { - static class Answer { - final int c; - final char[][] g; - Answer(int c, char[][] g) { this.c = c; this.g = g; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(c); - for (char[] row : g) { - sb.append('\n').append(row); - } - return sb.toString(); - } - } - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = Integer.parseInt(sc.next()); - int m = Integer.parseInt(sc.next()); - char[][] g = new char[n][]; - Arrays.setAll(g, i -> sc.next().toCharArray()); - sc.close(); - System.out.println(solve(n, m, g)); - } - - public static Answer solve(int n, int m, char[][] g) { +class practice2_d extends Solver { + public Answer solve(int n, int m, char[][] g) { MaxFlow mf = new MaxFlow(n * m + 2); int s = n * m; int t = s + 1; @@ -104,5 +94,160 @@ public static Answer solve(int n, int m, char[][] g) { if (ans != cnt) throw new AssertionError(); return new Answer(ans, g); } + + static class Answer { + final int c; + final char[][] g; + Answer(int c, char[][] g) { this.c = c; this.g = g; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(c); + for (char[] row : g) { + sb.append('\n').append(row); + } + return sb.toString(); + } + } + + public void run() { + Scanner sc = new Scanner(System.in); + int n = Integer.parseInt(sc.next()); + int m = Integer.parseInt(sc.next()); + char[][] g = new char[n][]; + Arrays.setAll(g, i -> sc.next().toCharArray()); + sc.close(); + System.out.println(solve(n, m, g)); + } } +/** + * @problem + * AtCoder Regular Contest 074 F - Lotus Leaves + * {@see https://atcoder.jp/contests/arc074/tasks/arc074_d} + * @submission + * {@see https://atcoder.jp/contests/arc074/submissions/20808863} + */ +class arc074_d extends Solver { + static final int INF = 1 << 20; + public int solve(int h, int w, char[][] g) { + int si = -1, sj = -1, ti = -1, tj = -1; + boolean[][] grid = new boolean[h][w]; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + if (g[i][j] == 'S') { + si = i; sj = j; + grid[i][j] = true; + } else if (g[i][j] == 'T') { + ti = i; tj = j; + grid[i][j] = true; + } else if (g[i][j] == 'o') { + grid[i][j] = true; + } + } + } + int s = h + w; + int t = s + 1; + MaxFlow mf = new MaxFlow(h + w + 2); + mf.addEdge(s , si , INF); + mf.addEdge(s , sj + h, INF); + mf.addEdge(ti , t , INF); + mf.addEdge(tj + h, t , INF); + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + if (grid[i][j]) { + mf.addEdge(i, j + h, 1); + mf.addEdge(j + h, i, 1); + } + } + } + int flow = (int) mf.maxFlow(s, t); + return flow >= INF ? -1 : flow; + } + + public void run() { + Scanner sc = new Scanner(System.in); + int h = Integer.parseInt(sc.next()); + int w = Integer.parseInt(sc.next()); + char[][] g = new char[h][]; + Arrays.setAll(g, i -> sc.next().toCharArray()); + sc.close(); + System.out.println(solve(h, w, g)); + } +} + +/** + * @problem + * AtCoder Beginner Contest 193 F - Zebraness + * {@see https://atcoder.jp/contests/abc193/tasks/abc193_f} + * @submission + * {@see https://atcoder.jp/contests/abc193/submissions/20808965} + */ +class abc193_f extends Solver { + static final int[] dx4 = {1, 0, -1, 0}; + static final int[] dy4 = {0, 1, 0, -1}; + + public int solve(int n, char[][] c) { + int[][] id = new int[n][n]; + int cnt = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (c[i][j] == '?') { + id[i][j] = cnt++; + } + } + } + + int ans = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i < n - 1) { + if (c[i][j] == 'B' && c[i + 1][j] == 'W' || c[i][j] == 'W' && c[i + 1][j] == 'B') { + ans++; + } + } + if (j < n - 1) { + if (c[i][j] == 'B' && c[i][j + 1] == 'W' || c[i][j] == 'W' && c[i][j + 1] == 'B') { + ans++; + } + } + } + } + MaxFlow mf = new MaxFlow(cnt + 2); + int s = cnt, t = cnt + 1; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (c[i][j] == '?') { + int b = 0, w = 0; + for (int d = 0; d < 4; d++) { + int ni = i + dx4[d]; + int nj = j + dy4[d]; + if (ni < 0 || ni >= n || nj < 0 || nj >= n) continue; + if (c[ni][nj] == 'B') { + b++; + } else if (c[ni][nj] == 'W') { + w++; + } else if (d < 2) { + mf.addEdge(id[i][j], id[ni][nj], 1); + mf.addEdge(id[ni][nj], id[i][j], 1); + ans++; + } + } + mf.addEdge(id[i][j], t, (i + j) % 2 == 1 ? b : w); + mf.addEdge(s, id[i][j], (i + j) % 2 == 1 ? w : b); + ans += b + w; + } + } + } + return (int) (ans - mf.maxFlow(s, t)); + } + + public void run() { + Scanner sc = new Scanner(System.in); + int n = Integer.parseInt(sc.next()); + char[][] c = new char[n][]; + Arrays.setAll(c, i -> sc.next().toCharArray()); + sc.close(); + System.out.println(solve(n, c)); + } +} From 1f919da3d7b6ef6cad9e0d410682f869909cd6d7 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Wed, 10 Mar 2021 19:28:20 +0900 Subject: [PATCH 33/48] Self loop handling (Min Cost Flow) #43 --- MinCostFlow/Main.java | 116 +++++++++++++ MinCostFlow/MinCostFlow.java | 282 +++++++++++++++---------------- MinCostFlow/MinCostFlowTest.java | 72 ++++++++ 3 files changed, 329 insertions(+), 141 deletions(-) create mode 100644 MinCostFlow/Main.java create mode 100644 MinCostFlow/MinCostFlowTest.java diff --git a/MinCostFlow/Main.java b/MinCostFlow/Main.java new file mode 100644 index 0000000..7b313ec --- /dev/null +++ b/MinCostFlow/Main.java @@ -0,0 +1,116 @@ +import java.util.Arrays; +import java.util.Scanner; + +public class Main { + static Solver practice2_e = new practice2_e(); + static Solver GRL_6_B = new GRL_6_B(); + + public static void main(String[] args) { + // practice2_e.run(); + GRL_6_B.run(); + } +} + +abstract class Solver implements Runnable { public abstract void run(); } + +/** + * @problem + * AtCoder Library Practice Contest E - MinCostFlow + * {@see https://atcoder.jp/contests/practice2/tasks/practice2_e} + * @submission + * {@see https://atcoder.jp/contests/practice2/submissions/20811599} + */ +class practice2_e extends Solver { + static class Answer { + final long ans; + final char[][] g; + Answer(long ans, char[][] g) { + this.ans = ans; + this.g = g; + } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(ans); + for (char[] r : g) { + sb.append('\n').append(r); + } + return sb.toString(); + } + } + public void run() { + Scanner sc = new Scanner(System.in); + int n = Integer.parseInt(sc.next()); + int k = Integer.parseInt(sc.next()); + long[][] a = new long[n][n]; + for (long[] r : a) Arrays.setAll(r, j -> Long.parseLong(sc.next())); + sc.close(); + System.out.println(solve(n, k, a)); + } + + static final long INF = 1l << 50; + + public Answer solve(int n, int k, long[][] a) { + MinCostFlow mcf = new MinCostFlow(n + n + 2); + int s = n + n , t = s + 1; + mcf.addEdge(s, t, n * k, INF); + + for(int i = 0; i < n; i++) { + mcf.addEdge(s, i, k, 0); + mcf.addEdge(i + n, t, k, 0); + } + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + mcf.addEdge(i, j + n, 1, INF - a[i][j]); + } + } + + MinCostFlow.FlowAndCost res = mcf.minCostFlow(s, t, n * k); + long ans = INF * res.flow - res.cost; + MinCostFlow.WeightedCapEdge[] es = mcf.getEdges(); + char[][] g = new char[n][n]; + for (char[] r : g) Arrays.fill(r, '.'); + for (MinCostFlow.WeightedCapEdge e : es) { + if (e.flow == 1 && e.from != s && e.to != t) { + g[e.from][e.to - n] = 'X'; + } + } + return new Answer(ans, g); + } +} + +/** + * @problem + * GRL_6 B - Minimum Cost Flow + * {@see https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_6_B} + * @submission + * {@see https://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=5281698#1} + */ +class GRL_6_B extends Solver { + public int solve(int n, int m, int f, int[][] edges) { + MinCostFlow mcf = new MinCostFlow(n); + for (int[] edge : edges) { + int u = edge[0]; + int v = edge[1]; + int c = edge[2]; + int d = edge[3]; + mcf.addEdge(u, v, c, d); + } + MinCostFlow.FlowAndCost fc = mcf.minCostFlow(0, n - 1, f); + return (int) (fc.flow == f ? fc.cost : -1); + } + + public void run() { + Scanner sc = new Scanner(System.in); + int v = Integer.parseInt(sc.next()); + int e = Integer.parseInt(sc.next()); + int f = Integer.parseInt(sc.next()); + int[][] edges = new int[e][4]; + for (int[] edge : edges) { + Arrays.setAll(edge, i -> Integer.parseInt(sc.next())); + } + sc.close(); + System.out.println(solve(v, e, f, edges)); + } +} diff --git a/MinCostFlow/MinCostFlow.java b/MinCostFlow/MinCostFlow.java index 8b57954..91689a7 100644 --- a/MinCostFlow/MinCostFlow.java +++ b/MinCostFlow/MinCostFlow.java @@ -1,48 +1,62 @@ /** - * @verified + * @verified * - https://atcoder.jp/contests/practice2/tasks/practice2_e * - http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_6_B */ class MinCostFlow { - public class WeightedCapEdge { - private final int from, to; - private long cap; - private long cost; - private final int rev; - WeightedCapEdge(int from, int to, long cap, long cost, int rev) { - this.from = from; - this.to = to; - this.cap = cap; - this.cost = cost; - this.rev = rev; + private static final class InternalWeightedCapEdge { + final int to, rev; + long cap; + final long cost; + InternalWeightedCapEdge(int to, int rev, long cap, long cost) { this.to = to; this.rev = rev; this.cap = cap; this.cost = cost; } + } + + public static final class WeightedCapEdge { + public final int from, to; + public final long cap, flow, cost; + WeightedCapEdge(int from, int to, long cap, long flow, long cost) { this.from = from; this.to = to; this.cap = cap; this.flow = flow; this.cost = cost; } + @Override + public boolean equals(Object o) { + if (o instanceof WeightedCapEdge) { + WeightedCapEdge e = (WeightedCapEdge) o; + return from == e.from && to == e.to && cap == e.cap && flow == e.flow && cost == e.cost; + } + return false; } - public int getFrom() {return from;} - public int getTo() {return to;} - public long getCap() {return cap;} - public long getCost() {return cost;} - public long getFlow() {return g[to][rev].cap;} } - private static final long INF = Long.MAX_VALUE; + private static final class IntPair { + final int first, second; + IntPair(int first, int second) { this.first = first; this.second = second; } + } - private final int n; - private int m; - private final java.util.ArrayList edges; - private final int[] count; - private final WeightedCapEdge[][] g; - private final long[] potential; + public static final class FlowAndCost { + public final long flow, cost; + FlowAndCost(long flow, long cost) { this.flow = flow; this.cost = cost; } + @Override + public boolean equals(Object o) { + if (o instanceof FlowAndCost) { + FlowAndCost c = (FlowAndCost) o; + return flow == c.flow && cost == c.cost; + } + return false; + } + } + + static final long INF = Long.MAX_VALUE; - private final long[] dist; - private final WeightedCapEdge[] prev; + private final int n; + private final java.util.ArrayList pos; + private final java.util.ArrayList[] g; + @SuppressWarnings("unchecked") public MinCostFlow(int n) { this.n = n; - this.edges = new java.util.ArrayList<>(); - this.count = new int[n]; - this.g = new WeightedCapEdge[n][]; - this.potential = new long[n]; - this.dist = new long[n]; - this.prev = new WeightedCapEdge[n]; + this.pos = new java.util.ArrayList<>(); + this.g = new java.util.ArrayList[n]; + for (int i = 0; i < n; i++) { + this.g[i] = new java.util.ArrayList<>(); + } } public int addEdge(int from, int to, long cap, long cost) { @@ -50,144 +64,130 @@ public int addEdge(int from, int to, long cap, long cost) { rangeCheck(to, 0, n); nonNegativeCheck(cap, "Capacity"); nonNegativeCheck(cost, "Cost"); - WeightedCapEdge e = new WeightedCapEdge(from, to, cap, cost, count[to]); - count[from]++; count[to]++; - edges.add(e); - return m++; + int m = pos.size(); + pos.add(new IntPair(from, g[from].size())); + int fromId = g[from].size(); + int toId = g[to].size(); + if (from == to) toId++; + g[from].add(new InternalWeightedCapEdge(to, toId, cap, cost)); + g[to].add(new InternalWeightedCapEdge(from, fromId, 0L, -cost)); + return m; } - private void buildGraph() { - for (int i = 0; i < n; i++) { - g[i] = new WeightedCapEdge[count[i]]; - } - int[] idx = new int[n]; - for (WeightedCapEdge e : edges) { - g[e.to][idx[e.to]++] = new WeightedCapEdge(e.to, e.from, 0, -e.cost, idx[e.from]); - g[e.from][idx[e.from]++] = e; - } + private InternalWeightedCapEdge getInternalEdge(int i) { + return g[pos.get(i).first].get(pos.get(i).second); } - private long addFlow; - private long addCost; - - public long[] minCostMaxFlow(int s, int t) { - return minCostFlow(s, t, INF); + private InternalWeightedCapEdge getInternalEdgeReversed(InternalWeightedCapEdge e) { + return g[e.to].get(e.rev); + } + + public WeightedCapEdge getEdge(int i) { + int m = pos.size(); + rangeCheck(i, 0, m); + InternalWeightedCapEdge e = getInternalEdge(i); + InternalWeightedCapEdge re = getInternalEdgeReversed(e); + return new WeightedCapEdge(re.to, e.to, e.cap + re.cap, re.cap, e.cost); } - public long[] minCostFlow(int s, int t, long flowLimit) { - rangeCheck(s, 0, n); - rangeCheck(t, 0, n); - if (s == t) { - throw new IllegalArgumentException(String.format("s = t = %d", s)); - } - nonNegativeCheck(flowLimit, "Flow"); - buildGraph(); - long flow = 0; - long cost = 0; - while (true) { - dijkstra(s, t, flowLimit - flow); - if (addFlow == 0) break; - flow += addFlow; - cost += addFlow * addCost; - } - return new long[]{flow, cost}; + public WeightedCapEdge[] getEdges() { + WeightedCapEdge[] res = new WeightedCapEdge[pos.size()]; + java.util.Arrays.setAll(res, this::getEdge); + return res; } - public java.util.ArrayList minCostSlope(int s, int t) { + public FlowAndCost minCostMaxFlow(int s, int t) { + return minCostFlow(s, t, INF); + } + public FlowAndCost minCostFlow(int s, int t, long flowLimit) { + return minCostSlope(s, t, flowLimit).getLast(); + } + java.util.LinkedList minCostSlope(int s, int t) { return minCostSlope(s, t, INF); } - public java.util.ArrayList minCostSlope(int s, int t, long flowLimit) { + public java.util.LinkedList minCostSlope(int s, int t, long flowLimit) { rangeCheck(s, 0, n); rangeCheck(t, 0, n); if (s == t) { - throw new IllegalArgumentException(String.format("s = t = %d", s)); + throw new IllegalArgumentException( + String.format("%d and %d is the same vertex.", s, t) + ); } - nonNegativeCheck(flowLimit, "Flow"); - buildGraph(); - java.util.ArrayList slope = new java.util.ArrayList<>(); - long prevCost = -1; + long[] dual = new long[n]; + long[] dist = new long[n]; + int[] pv = new int[n]; + int[] pe = new int[n]; + boolean[] vis = new boolean[n]; long flow = 0; - long cost = 0; - while (true) { - slope.add(new long[]{flow, cost}); - dijkstra(s, t, flowLimit - flow); - if (addFlow == 0) return slope; - flow += addFlow; - cost += addFlow * addCost; - if (addCost == prevCost) { - slope.remove(slope.size() - 1); + long cost = 0, prev_cost = -1; + java.util.LinkedList result = new java.util.LinkedList<>(); + result.addLast(new FlowAndCost(flow, cost)); + while (flow < flowLimit) { + if (!dualRef(s, t, dual, dist, pv, pe, vis)) break; + long c = flowLimit - flow; + for (int v = t; v != s; v = pv[v]) { + c = Math.min(c, g[pv[v]].get(pe[v]).cap); + } + for (int v = t; v != s; v = pv[v]) { + InternalWeightedCapEdge e = g[pv[v]].get(pe[v]); + e.cap -= c; + g[v].get(e.rev).cap += c; + } + long d = -dual[s]; + flow += c; + cost += c * d; + if (prev_cost == d) { + result.removeLast(); } - prevCost = addCost; + result.addLast(new FlowAndCost(flow, cost)); + prev_cost = cost; } + return result; } - private void dijkstra(int s, int t, long maxFlow) { - final class State implements Comparable { - final int v; - final long d; - State(int v, long d) {this.v = v; this.d = d;} - public int compareTo(State s) {return d == s.d ? v - s.v : d > s.d ? 1 : -1;} - } + private boolean dualRef(int s, int t, long[] dual, long[] dist, int[] pv, int[] pe, boolean[] vis) { java.util.Arrays.fill(dist, INF); - dist[s] = 0; + java.util.Arrays.fill(pv, -1); + java.util.Arrays.fill(pe, -1); + java.util.Arrays.fill(vis, false); + class State implements Comparable { + final long key; + final int to; + State(long key, int to) { this.key = key; this.to = to; } + public int compareTo(State q) { + return key > q.key ? 1 : -1; + } + }; java.util.PriorityQueue pq = new java.util.PriorityQueue<>(); - pq.add(new State(s, 0l)); + dist[s] = 0; + pq.add(new State(0L, s)); while (pq.size() > 0) { - State st = pq.poll(); - int u = st.v; - if (st.d != dist[u]) continue; - for (WeightedCapEdge e : g[u]) { - if (e.cap <= 0) continue; - int v = e.to; - long nextCost = dist[u] + e.cost + potential[u] - potential[v]; - if (nextCost < dist[v]) { - dist[v] = nextCost; - prev[v] = e; - pq.add(new State(v, dist[v])); + int v = pq.poll().to; + if (vis[v]) continue; + vis[v] = true; + if (v == t) break; + for (int i = 0, deg = g[v].size(); i < deg; i++) { + InternalWeightedCapEdge e = g[v].get(i); + if (vis[e.to] || e.cap == 0) continue; + long cost = e.cost - dual[e.to] + dual[v]; + if (dist[e.to] - dist[v] > cost) { + dist[e.to] = dist[v] + cost; + pv[e.to] = v; + pe[e.to] = i; + pq.add(new State(dist[e.to], e.to)); } } } - if (dist[t] == INF) { - addFlow = 0; - addCost = INF; - return; - } - for (int i = 0; i < n; i++) { - potential[i] += dist[i]; - } - addCost = 0; - addFlow = maxFlow; - for (int v = t; v != s;) { - WeightedCapEdge e = prev[v]; - addCost += e.cost; - addFlow = java.lang.Math.min(addFlow, e.cap); - v = e.from; - } - for (int v = t; v != s;) { - WeightedCapEdge e = prev[v]; - e.cap -= addFlow; - g[v][e.rev].cap += addFlow; - v = e.from; + if (!vis[t]) { + return false; } - } - public void clearFlow() { - java.util.Arrays.fill(potential, 0); - for (WeightedCapEdge e : edges) { - long flow = e.getFlow(); - e.cap += flow; - g[e.to][e.rev].cap -= flow; + for (int v = 0; v < n; v++) { + if (!vis[v]) continue; + dual[v] -= dist[t] - dist[v]; } - } - - public WeightedCapEdge getEdge(int i) { - rangeCheck(i, 0, m); - return edges.get(i); - } - - public java.util.ArrayList getEdges() { - return edges; + return true; } private void rangeCheck(int i, int minInlusive, int maxExclusive) { diff --git a/MinCostFlow/MinCostFlowTest.java b/MinCostFlow/MinCostFlowTest.java new file mode 100644 index 0000000..9a773b1 --- /dev/null +++ b/MinCostFlow/MinCostFlowTest.java @@ -0,0 +1,72 @@ +import static org.junit.Assert.assertEquals; + +import java.util.LinkedList; + +import org.junit.Test; + +public class MinCostFlowTest { + @Test + public void simple() { + MinCostFlow g = new MinCostFlow(4); + g.addEdge(0, 1, 1, 1); + g.addEdge(0, 2, 1, 1); + g.addEdge(1, 3, 1, 1); + g.addEdge(2, 3, 1, 1); + g.addEdge(1, 2, 1, 1); + LinkedList expect = new LinkedList<>(); + expect.add(new MinCostFlow.FlowAndCost(0, 0)); + expect.add(new MinCostFlow.FlowAndCost(2, 4)); + assertEquals(expect, g.minCostSlope(0, 3, 10)); + MinCostFlow.WeightedCapEdge e; + + e = new MinCostFlow.WeightedCapEdge(0, 1, 1, 1, 1); + assertEquals(e, g.getEdge(0)); + e = new MinCostFlow.WeightedCapEdge(0, 2, 1, 1, 1); + assertEquals(e, g.getEdge(1)); + e = new MinCostFlow.WeightedCapEdge(1, 3, 1, 1, 1); + assertEquals(e, g.getEdge(2)); + e = new MinCostFlow.WeightedCapEdge(2, 3, 1, 1, 1); + assertEquals(e, g.getEdge(3)); + e = new MinCostFlow.WeightedCapEdge(1, 2, 1, 0, 1); + assertEquals(e, g.getEdge(4)); + } + + @Test + public void usage() { + { + MinCostFlow g = new MinCostFlow(2); + g.addEdge(0, 1, 1, 2); + assertEquals(new MinCostFlow.FlowAndCost(1, 2), g.minCostMaxFlow(0, 1)); + } + { + MinCostFlow g = new MinCostFlow(2); + g.addEdge(0, 1, 1, 2); + LinkedList expect = new LinkedList<>(); + expect.add(new MinCostFlow.FlowAndCost(0, 0)); + expect.add(new MinCostFlow.FlowAndCost(1, 2)); + assertEquals(expect, g.minCostSlope(0, 1)); + } + } + + @Test + public void outOfRange() { + MinCostFlow g = new MinCostFlow(10); + try { + g.minCostSlope(-1, 3); + throw new AssertionError(); + } catch (Exception e) {} + try { + g.minCostSlope(3, 3); + throw new AssertionError(); + } catch (Exception e) {} + } + + @Test + public void selfLoop() { + MinCostFlow g = new MinCostFlow(3); + assertEquals(0, g.addEdge(0, 0, 100, 123)); + + MinCostFlow.WeightedCapEdge e = new MinCostFlow.WeightedCapEdge(0, 0, 100, 0, 123); + assertEquals(e, g.getEdge(0)); + } +} From de817782235bc95553ba74f4f293444cdf9067b7 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Wed, 10 Mar 2021 19:47:26 +0900 Subject: [PATCH 34/48] fix access modifiers of members of MaxFlow.CapEdge --- MaxFlow/MaxFlow.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MaxFlow/MaxFlow.java b/MaxFlow/MaxFlow.java index 3995c07..591fc2f 100644 --- a/MaxFlow/MaxFlow.java +++ b/MaxFlow/MaxFlow.java @@ -6,8 +6,8 @@ private static final class InternalCapEdge { InternalCapEdge(int to, int rev, long cap) { this.to = to; this.rev = rev; this.cap = cap; } } public static final class CapEdge { - final int from, to; - final long cap, flow; + public final int from, to; + public final long cap, flow; CapEdge(int from, int to, long cap, long flow) { this.from = from; this.to = to; this.cap = cap; this.flow = flow; } @Override public boolean equals(Object o) { From 0495145943543c37eeaa181517ad90d34dbc6106 Mon Sep 17 00:00:00 2001 From: suisen-cp Date: Wed, 10 Mar 2021 19:47:50 +0900 Subject: [PATCH 35/48] fix Readme of MaxFlow/MinCostFlow --- MaxFlow/Readme.md | 31 +++++++++++---------------- MinCostFlow/Readme.md | 50 ++++++++++++++++--------------------------- 2 files changed, 31 insertions(+), 50 deletions(-) diff --git a/MaxFlow/Readme.md b/MaxFlow/Readme.md index 2e2df9d..a4781d3 100644 --- a/MaxFlow/Readme.md +++ b/MaxFlow/Readme.md @@ -38,16 +38,10 @@ public void addEdge(int from, int to, long cap) public long maxFlow(int s, int t) // (2) public long flow(int s, int t, long flowLimit) -// (3) -public long fordFulkersonMaxFlow(int s, int t) -// (4) -public long fordFulkersonFlow(int s, int t, long flowLimit) ``` - (1): 頂点 `s` から `t` へ流せる限り流し、流せた量を返す。Dinic のアルゴルズムを用います。 - (2) 頂点 `s` から `t` へ流量 `flowLimit` に達するまで流せる限り流し、流せた量を返す。Dinic のアルゴルズムを用います。 -- (3) 頂点 `s` から `t` へ流せる限り流し、流せた量を返す。FordFulkerson のアルゴルズムを用います。 -- (4) 頂点 `s` から `t` へ流量 `flowLimit` に達するまで流せる限り流し、流せた量を返す。FordFulkerson のアルゴルズムを用います。 - 複数回呼んだ場合は,前回流したフローからの差分が返ります。 制約 @@ -60,7 +54,6 @@ public long fordFulkersonFlow(int s, int t, long flowLimit) - (1), (2) $O(\min(n^{2/3}*m, m^{3/2}))$ (辺の容量がすべて 1 の時) - (1), (2) $O(n^2*m)$ -- (3), (4) 返り値を `f` として,`O(f*m)` ### minCut @@ -76,34 +69,34 @@ public boolean[] minCut(int s) ### getEdge / getEdges -`getEdge`、`getEdges` の返り値には以下のメソッドを持つ `MaxFlow.CapEdge` 型が用いられています。 +`getEdge`、`getEdges` の返り値には以下のメンバを持つ `MaxFlow.CapEdge` 型が用いられています。 ```java class CapEdge { // (1) - public int getFrom() + public final int from; // (2) - public int getTo() + public final int to; // (3) - public long getCap() + public final long cap; // (4) - public long getFlow() + public final long flow; }; ``` -- (1): 始点を返します。計算量: $O(1)$ -- (2): 終点を返します。計算量: $O(1)$ -- (3): 現在の容量を返します。計算量: $O(1)$ +- (1): 辺の始点を返します。計算量: $O(1)$ +- (2): 辺の終点を返します。計算量: $O(1)$ +- (3): 辺の容量を返します。計算量: $O(1)$ - (4): 現在の流量を返しまず。計算量: $O(1)$ ```java // (1) public CapEdge getEdge(int i) // (2) -public java.util.ArrayList getEdges() +public CapEdge[] getEdges() ``` -今の内部の辺の状態を返す。辺の順番は `addEdge` で追加された順番と同一。 +現在の内部の辺の状態を返す。辺の順番は `addEdge` で追加された順番と同一。 制約 @@ -112,7 +105,7 @@ public java.util.ArrayList getEdges() 計算量 - (1): $O(1)$ -- (2): $O(1)$ +- (2): $O(m)$ ### changeEdge @@ -132,4 +125,4 @@ $O(1) ## 使用例 -[AtCoder Library Practice Contest D - Maxflow](https://atcoder.jp/contests/practice2/submissions/16646346) +[AtCoder Library Practice Contest D - Maxflow](https://atcoder.jp/contests/practice2/submissions/20808482) diff --git a/MinCostFlow/Readme.md b/MinCostFlow/Readme.md index 88508ad..4244870 100644 --- a/MinCostFlow/Readme.md +++ b/MinCostFlow/Readme.md @@ -35,12 +35,12 @@ public int addEdge(int from, int to, long cap, long cost) ```java // (1) -public long[] minCostMaxFlow(int s, int t) +public MinCostFlow.FlowAndCost minCostMaxFlow(int s, int t) // (2) -public long[] minCostFlow(int s, int t, long flowLimit) +public MinCostFlow.FlowAndCost minCostFlow(int s, int t, long flowLimit) ``` -`s` から `t` へ流せるだけ流し、その流量とコストを返す。返り値は長さ 2 の配列で表現され、中身は `{flow, cost}` である。 +`s` から `t` へ流せるだけ流し、その流量とコストを返す。返り値は `MinCostFlow.FlowAndCost` であり,メンバに `long flow` と `long cost` を持つ. - (1): `s` から `t` へ流せるだけ流す - (2): `s` から `t` へ流量 `flowLimit` まで流せるだけ流す @@ -57,9 +57,9 @@ public long[] minCostFlow(int s, int t, long flowLimit) ```java // (1) -public java.util.ArrayList minCostSlope(int s, int t) +public java.util.ArrayList minCostSlope(int s, int t) // (2) -public java.util.ArrayList minCostSlope(int s, int t, long flowLimit) +public java.util.ArrayList minCostSlope(int s, int t, long flowLimit) ``` 返り値に流量とコストの関係の折れ線が入る。全ての `x` について、流量 `x` の時の最小コストを `g(x)` とすると、`{x, g(x)}` は返り値を折れ線として見たものに含まれる。返り値のリストは以下のような性質を満たします。 @@ -73,24 +73,12 @@ public java.util.ArrayList minCostSlope(int s, int t, long flowLimit) 制約 - `s != t` -- `minCostSlope` や `minCostFlow` を合わせて複数回呼んだときの挙動は未定義 (複数回フローを流す場合は後述の `clearFlow` メソッドによりフローをリセットしてください) +- `minCostSlope` や `minCostFlow` を合わせて複数回呼んだときの挙動は未定義 計算量 `F` を流量、`m` を追加した辺の本数として $O(F (n + m) \log n)$ -### clearFlow - -```java -public void clearFlow() -``` - -全ての辺に流れているフローを 0 にします。 - -計算量 - -`m` を追加した辺の本数として $O(n + m)$ - ### getEdge / getEdges `getEdge`、`getEdges` の返り値には以下のメソッドを持つ `MinCostFlow.WeightedCapEdge` 型が用いられています。 @@ -98,29 +86,29 @@ public void clearFlow() ```java class WeightedCapEdge { // (1) - public int getFrom() + public final int from; // (2) - public int getTo() + public final int to; // (3) - public long getCap() + public final long cap; // (4) - public long getCost() + public final long flow; // (4) - public long getFlow() + public final long cost; }; ``` -- (1): 始点を返します。計算量: $O(1)$ -- (2): 終点を返します。計算量: $O(1)$ -- (3): 現在の容量を返します。計算量: $O(1)$ -- (4): コストを返します。計算量: $O(1)$ +- (1): 辺の始点を返します。計算量: $O(1)$ +- (2): 辺の終点を返します。計算量: $O(1)$ +- (3): 辺の容量を返します。計算量: $O(1)$ +- (4): 辺のコストを返します。計算量: $O(1)$ - (5): 現在の流量を返しまず。計算量: $O(1)$ ```java // (1) -public CapEdge getEdge(int i) +public WeightedCapEdge getEdge(int i) // (2) -public java.util.ArrayList getEdges() +public WeightedCapEdge[] getEdges() ``` 今の内部の辺の状態を返す。辺の順番は `addEdge` で追加された順番と同一。 @@ -132,8 +120,8 @@ public java.util.ArrayList getEdges() 計算量 - (1): $O(1)$ -- (2): $O(1)$ +- (2): $O(m)$ 使用例 -[AtCoder Library Practice Contest E - MinCostFlow](https://atcoder.jp/contests/practice2/submissions/16654383) +[AtCoder Library Practice Contest E - MinCostFlow](https://atcoder.jp/contests/practice2/submissions/20811599) From b6d70088062ef0f4cd2d861be60e03bf6f9362a1 Mon Sep 17 00:00:00 2001 From: sounansya Date: Fri, 12 Mar 2021 18:31:16 +0900 Subject: [PATCH 36/48] Fix printArray bug --- ContestIO/ContestPrinter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ContestIO/ContestPrinter.java b/ContestIO/ContestPrinter.java index 49eb259..ac8b745 100644 --- a/ContestIO/ContestPrinter.java +++ b/ContestIO/ContestPrinter.java @@ -60,10 +60,10 @@ public void printArray(int[] array, String separator, java.util.function.IntUnar super.print(map.applyAsInt(array[i])); super.print(separator); } - super.println(array[n-1]); + super.println(map.applyAsInt(array[n-1])); } public void printArray(int[] array, java.util.function.IntUnaryOperator map){ - this.printArray(array, map); + this.printArray(array, " ", map); } public void printArray(long[] array, String separator){ @@ -83,10 +83,10 @@ public void printArray(long[] array, String separator, java.util.function.LongUn super.print(map.applyAsLong(array[i])); super.print(separator); } - super.println(array[n-1]); + super.println(map.applyAsLong(array[n-1])); } - public void printArray(long[] array, java.util.function.IntUnaryOperator map){ - this.printArray(array, map); + public void printArray(long[] array, java.util.function.LongUnaryOperator map){ + this.printArray(array, " ", map); } } \ No newline at end of file From d5af2ab6a0cddfe233364ffbd8f203c12e2ba43e Mon Sep 17 00:00:00 2001 From: NASU41 Date: Sat, 22 May 2021 14:08:23 +0900 Subject: [PATCH 37/48] fix Pair::compareTo --- Pair/Pair.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Pair/Pair.java b/Pair/Pair.java index decc8c6..b5a30a7 100644 --- a/Pair/Pair.java +++ b/Pair/Pair.java @@ -13,8 +13,9 @@ public boolean equals(Object another){ return this.first.equals(otherPair.first) && this.second.equals(otherPair.second); } public int compareTo(Pair another){ - if(this.second.compareTo(another.second) == 0) return this.first.compareTo(another.first); - else return this.second.compareTo(another.second); + Comparator> comp1 = Comparator.comparing(Pair::getFirst); + Comparator> comp2 = comp1.thenComparing(Pair::getSecond); + return comp2.compare(this, another); } public int hashCode(){ return first.hashCode() * 10007 + second.hashCode(); From c14214235642346ecc72f0673e10520fe169e025 Mon Sep 17 00:00:00 2001 From: NASU41 Date: Sun, 30 May 2021 23:36:54 +0900 Subject: [PATCH 38/48] Update Pair.java --- Pair/Pair.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Pair/Pair.java b/Pair/Pair.java index b5a30a7..c7f1581 100644 --- a/Pair/Pair.java +++ b/Pair/Pair.java @@ -6,6 +6,8 @@ public Pair(S s, T t){ first = s; second = t; } + public S getFirst(){return first;} + public T getSecond(){return second;} public boolean equals(Object another){ if(this==another) return true; if(!(another instanceof Pair)) return false; @@ -13,8 +15,8 @@ public boolean equals(Object another){ return this.first.equals(otherPair.first) && this.second.equals(otherPair.second); } public int compareTo(Pair another){ - Comparator> comp1 = Comparator.comparing(Pair::getFirst); - Comparator> comp2 = comp1.thenComparing(Pair::getSecond); + java.util.Comparator> comp1 = java.util.Comparator.comparing(Pair::getFirst); + java.util.Comparator> comp2 = comp1.thenComparing(Pair::getSecond); return comp2.compare(this, another); } public int hashCode(){ @@ -23,4 +25,4 @@ public int hashCode(){ public String toString(){ return String.format("(%s, %s)", first, second); } -} +} \ No newline at end of file From 16afefe17c32f8b7a90f06490b4ed1afc5f2e72e Mon Sep 17 00:00:00 2001 From: NASU41 Date: Sun, 30 May 2021 23:44:06 +0900 Subject: [PATCH 39/48] fixed ComtestPrinter::printArray With the old implementation, ContestPrinter throws unintended exception when the length of the array is zero. The bug is now removed! --- ContestIO/ContestPrinter.java | 47 ++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/ContestIO/ContestPrinter.java b/ContestIO/ContestPrinter.java index ac8b745..183576d 100644 --- a/ContestIO/ContestPrinter.java +++ b/ContestIO/ContestPrinter.java @@ -45,6 +45,10 @@ public void println(double d){ public void printArray(int[] array, String separator){ int n = array.length; + if(n==0){ + super.println(); + return; + } for(int i=0; i Date: Mon, 31 May 2021 00:50:16 +0900 Subject: [PATCH 40/48] Update ContestPrinter.java --- ContestIO/ContestPrinter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ContestIO/ContestPrinter.java b/ContestIO/ContestPrinter.java index 183576d..c60b717 100644 --- a/ContestIO/ContestPrinter.java +++ b/ContestIO/ContestPrinter.java @@ -104,7 +104,7 @@ public void printArray(long[] array, String separator, java.util.function.LongUn public void printArray(long[] array, java.util.function.LongUnaryOperator map){ this.printArray(array, " ", map); } - public void printArray(Object[] array, String separator){ + public void printArray(T[] array, String separator){ int n = array.length; if(n==0){ super.println(); @@ -116,10 +116,10 @@ public void printArray(Object[] array, String separator){ } super.println(array[n-1]); } - public void printArray(Object[] array){ + public void printArray(T[] array){ this.printArray(array, " "); } - public void printArray(Object[] array, String separator, java.util.function.UnaryOperator map){ + public void printArray(T[] array, String separator, java.util.function.UnaryOperator map){ int n = array.length; if(n==0){ super.println(); @@ -131,7 +131,7 @@ public void printArray(Object[] array, String separator, java.util.function.Unar } super.println(map.apply(array[n-1])); } - public void printArray(Object[] array, java.util.function.UnaryOperator map){ + public void printArray(T[] array, java.util.function.UnaryOperator map){ this.printArray(array, " ", map); } -} \ No newline at end of file +} From 870991aefd30ebe5878fc6f2d0ebfecf1df96a5d Mon Sep 17 00:00:00 2001 From: NASU41 Date: Wed, 9 Jun 2021 16:17:38 +0900 Subject: [PATCH 41/48] variadic MathLib.gcd --- Math/MathLib.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Math/MathLib.java b/Math/MathLib.java index 5a309da..a99167b 100644 --- a/Math/MathLib.java +++ b/Math/MathLib.java @@ -22,16 +22,27 @@ private static long[] inv_gcd(long a, long b){ return new long[]{s,m0}; } - public static long gcd(long a, long b){ - a = java.lang.Math.abs(a); - b = java.lang.Math.abs(b); - return inv_gcd(a, b)[0]; + public static long gcd(long... a){ + if(a.length == 0) return 0; + long r = java.lang.Math.abs(a[0]); + for(int i=1; i= 0; From 057f39944dae6c72ea902ef352955c213faaf9c4 Mon Sep 17 00:00:00 2001 From: NASU41 Date: Wed, 9 Jun 2021 16:18:08 +0900 Subject: [PATCH 42/48] variadic MathLib.lcm --- Math/MathLib.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Math/MathLib.java b/Math/MathLib.java index a99167b..049cb94 100644 --- a/Math/MathLib.java +++ b/Math/MathLib.java @@ -30,11 +30,7 @@ public static long gcd(long... a){ } return r; } - public static long lcm(long a, long b){ - a = java.lang.Math.abs(a); - b = java.lang.Math.abs(b); - return a / gcd(a,b) * b; - } + public static long lcm(long... a){ if(a.length == 0) return 0; long r = java.lang.Math.abs(a[0]); From c0c653f0fc9065619ac1dcf69501d0d4c1040d7d Mon Sep 17 00:00:00 2001 From: NASU41 Date: Fri, 11 Jun 2021 13:25:16 +0900 Subject: [PATCH 43/48] fix MathLib.gcd --- Math/MathLib.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Math/MathLib.java b/Math/MathLib.java index 049cb94..c85cf34 100644 --- a/Math/MathLib.java +++ b/Math/MathLib.java @@ -26,7 +26,10 @@ public static long gcd(long... a){ if(a.length == 0) return 0; long r = java.lang.Math.abs(a[0]); for(int i=1; i Date: Wed, 30 Jun 2021 00:35:55 +0900 Subject: [PATCH 44/48] =?UTF-8?q?ModInt=E3=81=AE=E3=83=90=E3=82=B0?= =?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3=E7=AD=89=E3=82=92=E3=81=97=E3=81=BE?= =?UTF-8?q?=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 12292 bytes ModInt/.DS_Store | Bin 0 -> 6148 bytes ModInt/ModInt.java | 14 ++++++++++---- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .DS_Store create mode 100644 ModInt/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..14342394181007248690bd805073cccd818e0589 GIT binary patch literal 12292 zcmeHNO>7%Q6n>kZW}T!>A|cUB#EPE^L==+#P$-JXe-#8Y!YN3U(%7+;SlHgkc52#? zC7GI=KJ8TJzEc058TlnP~(G#L)DXEy%W@W=)g&(@Ty&<@VekyCG6^+7uJ(u zy%W@EL2&|A)PbrKE-{=y9rwLZZZfQQf;vzqM?V>M!Y4c73dPY+$9+$WlQS9A_G~?1 zJ<#ldW4P5t&rpVHw6;(btL{(n8Z}nkOs=>(o?h`w>w&qUZ@G<^| zxocChJ-283`Wm#kI@*B9# zQWE`+Lf;4U1uA22!>1~|oXA4&aNLY`IE-47&67Wy?Q>S8n-MDm8qTh@v}C!cSndN$ zpK{p4DN{{Gh*Uq~+=OhlUR@9S%MaQ0Vxd|a8~elQ=ufXPx~9? zTvgji2Mw;9a#QC94{mNAd;IW-cVz77)`+)x{P@_2cl5}kTU#mj?gz#v7M4pFE^fZI zwf&)D3{v4-L<7O^==>3`1W6gTGoQ!Xd9eQMes{ME3L88`CK(x+Wd%ssIG?VRi+)*c z*eUETg0_K|s)i0)rF=Ya`qkorYm%3|-0dWroZGE?B5qB#IKRE*Bu5XA!~nL40jxlk zSjWS_)A2HUsUkUvyXP}*gX2B)6dS<8XKB#d&>Ba!pS~`Jcik`#v?-b3VSIyBV*ybcd)t>~zPHYv=(2SH) zLt)1+ENY>Y+Eaf;Xk&JGFEdLepdSGG8j!0gXBECI;_U0+nBb`-+31LHHZ8OzyZe>9T4-># zhx*^!9obrHHDcDjR)RN_|821zupY1;upY1;upWqc0RI6%`aFsxp+Ge;y?4I;F>m7& zx%&Pdt?NTwp0Fgfi^;iXP{HV;!$?-9Xh|j|DgmTXmHJa2p)oL%+Vgn`lJ3 z9A8qqz(+a}90HPxUL39HWs=$>(TO|Kd0!`32`gQJybTMIQ|b|LYD0^&eR$~7F59*= z8>!XpX(o7RA5H7jGKc;XOO#b=DSRPhCF}i*kQMEm-|r_PeleK_6O&8==9J!v!7c@o zd$k|4K&KM=-xb#X5;P?Ki5tM5AjMhC-xn<<6D1p5_Lh{4l;g1cQ+rEgI*)TvFEI_v zOX92yT9VoLk7oOv-SxMk7#ZyH_ph~d0?SS;EYoya#!B}x&MK6WEDn4L7GVoVefg6J zb=2C3LvyP{<-sU?KaYM?raH!h6?(<6XvB!-9AG`lpe0eKUNqb1EUtbZu`t->zHcp^ zz_OoC;yusMI+l>r=wSu)vmAKGH(and7Ceo5lIg$)U}}`*T>rTdaot0{5yN)mC0{-A z_u=1Y8M;Up_Syi|LB>V*IPsqg=D z=Kud`A$zhOupan-dcf(LP0vn)n`7XozO{QemT@SVZ*ZuBYpsHl{v3~5e~w43KgXli z!)Yix8P+>NjaHQZ{EqNi6n6d(atuBz Swlkme7`7uXqk5;z|NjD6+PyOX literal 0 HcmV?d00001 diff --git a/ModInt/.DS_Store b/ModInt/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8415c2b40572f3cdd2c529f57d935b126e00e321 GIT binary patch literal 6148 zcmeHKF;c@Y5L`iuFlka!>IIphqZApZNI?T1Ai)(A;s&VQR0Bg2v zIx~zh6bJ=EfiDI0f5>!UaqJE2uY-fG@7kXTWt`Vuf|z|>9D76V(2`M!Mor#gB%?E) zJ+C{*?l0 z(%d&oev;SL(Z{LQX8HsD)0kV+ISeiVT&NUZp5$fCnO7Wp!%Ano(ur{qkS<}Nz+Wiv E0fKKSwg3PC literal 0 HcmV?d00001 diff --git a/ModInt/ModInt.java b/ModInt/ModInt.java index 6409d7d..fcbf5dc 100644 --- a/ModInt/ModInt.java +++ b/ModInt/ModInt.java @@ -43,8 +43,14 @@ public ModInt create(long value) { private void prepareFactorial(int max){ factorial.ensureCapacity(max+1); if(factorial.size()==0) factorial.add(1); - for(int i=factorial.size(); i<=max; i++){ - factorial.add(ma.mul(factorial.get(i-1), i)); + if (usesMontgomery) { + for(int i=factorial.size(); i<=max; i++){ + factorial.add(ma.mul(factorial.get(i-1), maMontgomery.generate(i))); + } + } else { + for(int i=factorial.size(); i<=max; i++){ + factorial.add(ma.mul(factorial.get(i-1), i)); + } } } @@ -77,8 +83,8 @@ public int mod() { return mod; } public int value() { - if (ma instanceof ModArithmetic.ModArithmeticMontgomery) { - return ((ModArithmetic.ModArithmeticMontgomery) ma).reduce(value); + if (usesMontgomery) { + return maMontgomery.reduce(value); } return value; } From cf83fc3e5f112120b2df846bd60b38fef6f9d82b Mon Sep 17 00:00:00 2001 From: NASU41 Date: Sat, 10 Jul 2021 23:11:54 +0900 Subject: [PATCH 45/48] add ContestIO(File) --- ContestIO/ContestPrinter.java | 3 +++ ContestIO/ContestScanner.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ContestIO/ContestPrinter.java b/ContestIO/ContestPrinter.java index c60b717..545045d 100644 --- a/ContestIO/ContestPrinter.java +++ b/ContestIO/ContestPrinter.java @@ -2,6 +2,9 @@ class ContestPrinter extends java.io.PrintWriter{ public ContestPrinter(java.io.PrintStream stream){ super(stream); } + public ContestPrinter(java.io.File file) throws java.io.FileNotFoundException{ + super(new java.io.PrintStream(file)); + } public ContestPrinter(){ super(System.out); } diff --git a/ContestIO/ContestScanner.java b/ContestIO/ContestScanner.java index 2878ec6..3d3c80e 100644 --- a/ContestIO/ContestScanner.java +++ b/ContestIO/ContestScanner.java @@ -11,6 +11,9 @@ class ContestScanner { public ContestScanner(java.io.InputStream in){ this.in = in; } + public ContestScanner(java.io.File file) throws java.io.FileNotFoundException { + this(new java.io.BufferedInputStream(new java.io.FileInputStream(file))); + } public ContestScanner(){ this(System.in); } From a649af528f8e969d51b7fc572d3d45f9e3f8b6dd Mon Sep 17 00:00:00 2001 From: Hiromi Ayase Date: Fri, 23 Jul 2021 00:32:53 +0900 Subject: [PATCH 46/48] fix https://github.com/atcoder/ac-library/issues/30 --- .vscode/settings.json | 6 ++++++ Convolution/Convolution.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d777ab6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "java.project.sourcePaths": [ + "Convolution", + "ModInt" + ] +} \ No newline at end of file diff --git a/Convolution/Convolution.java b/Convolution/Convolution.java index da1ff29..9e1c769 100644 --- a/Convolution/Convolution.java +++ b/Convolution/Convolution.java @@ -125,7 +125,7 @@ private static long[] sumE(int mod, int g) { ie = ie * ie % mod; } long now = 1; - for (int i = 0; i < cnt2 - 2; i++) { + for (int i = 0; i <= cnt2 - 2; i++) { sum_e[i] = es[i] * now % mod; now = now * ies[i] % mod; } @@ -154,7 +154,7 @@ private static long[] sumIE(int mod, int g) { ie = ie * ie % mod; } long now = 1; - for (int i = 0; i < cnt2 - 2; i++) { + for (int i = 0; i <= cnt2 - 2; i++) { sum_ie[i] = ies[i] * now % mod; now = now * es[i] % mod; } From 239c2b89bfb9c1f2de965d5bc6d5a6c67d939b87 Mon Sep 17 00:00:00 2001 From: Hiromi Ayase Date: Fri, 23 Jul 2021 03:22:54 +0900 Subject: [PATCH 47/48] 4-base NTT --- Convolution/Convolution.java | 263 +++++++++++++++++++++++------------ 1 file changed, 171 insertions(+), 92 deletions(-) diff --git a/Convolution/Convolution.java b/Convolution/Convolution.java index 9e1c769..e5c6a16 100644 --- a/Convolution/Convolution.java +++ b/Convolution/Convolution.java @@ -1,8 +1,8 @@ /** * Convolution. * - * @verified https://atcoder.jp/contests/practice2/tasks/practice2_f - * @verified https://judge.yosupo.jp/problem/convolution_mod_1000000007 + * @verified https://atcoder.jp/contests/practice2/submissions/24449847 + * @verified https://judge.yosupo.jp/submission/53841 */ class Convolution { /** @@ -78,6 +78,74 @@ private static int ceilPow2(int n) { return x; } + private static class FftInfo { + private static int bsfConstexpr(int n) { + int x = 0; + while ((n & (1 << x)) == 0) x++; + return x; + } + + private static long inv(long a, long mod) { + long b = mod; + long p = 1, q = 0; + while (b > 0) { + long c = a / b; + long d; + d = a; + a = b; + b = d % b; + d = p; + p = q; + q = d - c * q; + } + return p < 0 ? p + mod : p; + } + + private final int rank2; + public final long[] root; + public final long[] iroot; + public final long[] rate2; + public final long[] irate2; + public final long[] rate3; + public final long[] irate3; + + public FftInfo(int g, int mod) { + rank2 = bsfConstexpr(mod - 1); + root = new long[rank2 + 1]; + iroot = new long[rank2 + 1]; + rate2 = new long[Math.max(0, rank2 - 2 + 1)]; + irate2 = new long[Math.max(0, rank2 - 2 + 1)]; + rate3 = new long[Math.max(0, rank2 - 3 + 1)]; + irate3 = new long[Math.max(0, rank2 - 3 + 1)]; + + root[rank2] = pow(g, (mod - 1) >> rank2, mod); + iroot[rank2] = inv(root[rank2], mod); + for (int i = rank2 - 1; i >= 0; i--) { + root[i] = root[i + 1] * root[i + 1] % mod; + iroot[i] = iroot[i + 1] * iroot[i + 1] % mod; + } + + { + long prod = 1, iprod = 1; + for (int i = 0; i <= rank2 - 2; i++) { + rate2[i] = root[i + 2] * prod % mod; + irate2[i] = iroot[i + 2] * iprod % mod; + prod = prod * iroot[i + 2] % mod; + iprod = iprod * root[i + 2] % mod; + } + } + { + long prod = 1, iprod = 1; + for (int i = 0; i <= rank2 - 3; i++) { + rate3[i] = root[i + 3] * prod % mod; + irate3[i] = iroot[i + 3] * iprod % mod; + prod = prod * iroot[i + 3] % mod; + iprod = iprod * root[i + 3] % mod; + } + } + } + }; + /** * Garner's algorithm. * @@ -104,87 +172,65 @@ private static long garner(long[] c, int[] mods) { return cnst[n - 1]; } - /** - * Pre-calculation for NTT. - * - * @param mod NTT Prime. - * @param g Primitive root of mod. - * @return Pre-calculation table. - */ - private static long[] sumE(int mod, int g) { - long[] sum_e = new long[30]; - long[] es = new long[30]; - long[] ies = new long[30]; - int cnt2 = Integer.numberOfTrailingZeros(mod - 1); - long e = pow(g, (mod - 1) >> cnt2, mod); - long ie = pow(e, mod - 2, mod); - for (int i = cnt2; i >= 2; i--) { - es[i - 2] = e; - ies[i - 2] = ie; - e = e * e % mod; - ie = ie * ie % mod; - } - long now = 1; - for (int i = 0; i <= cnt2 - 2; i++) { - sum_e[i] = es[i] * now % mod; - now = now * ies[i] % mod; - } - return sum_e; - } - - /** - * Pre-calculation for inverse NTT. - * - * @param mod Mod. - * @param g Primitive root of mod. - * @return Pre-calculation table. - */ - private static long[] sumIE(int mod, int g) { - long[] sum_ie = new long[30]; - long[] es = new long[30]; - long[] ies = new long[30]; - - int cnt2 = Integer.numberOfTrailingZeros(mod - 1); - long e = pow(g, (mod - 1) >> cnt2, mod); - long ie = pow(e, mod - 2, mod); - for (int i = cnt2; i >= 2; i--) { - es[i - 2] = e; - ies[i - 2] = ie; - e = e * e % mod; - ie = ie * ie % mod; - } - long now = 1; - for (int i = 0; i <= cnt2 - 2; i++) { - sum_ie[i] = ies[i] * now % mod; - now = now * es[i] % mod; - } - return sum_ie; - } - /** * Inverse NTT. * * @param a Target array. - * @param sumIE Pre-calculation table. + * @param g Primitive root of mod. * @param mod NTT Prime. */ - private static void butterflyInv(long[] a, long[] sumIE, int mod) { + private static void butterflyInv(long[] a, int g, int mod) { int n = a.length; int h = ceilPow2(n); - for (int ph = h; ph >= 1; ph--) { - int w = 1 << (ph - 1), p = 1 << (h - ph); - long inow = 1; - for (int s = 0; s < w; s++) { - int offset = s << (h - ph + 1); - for (int i = 0; i < p; i++) { - long l = a[i + offset]; - long r = a[i + offset + p]; - a[i + offset] = (l + r) % mod; - a[i + offset + p] = (mod + l - r) * inow % mod; + FftInfo info = new FftInfo(g, mod); + + int len = h; // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed + while (len > 0) { + if (len == 1) { + int p = 1 << (h - len); + long irot = 1; + for (int s = 0; s < (1 << (len - 1)); s++) { + int offset = s << (h - len + 1); + for (int i = 0; i < p; i++) { + long l = a[i + offset]; + long r = a[i + offset + p]; + a[i + offset] = (l + r) % mod; + a[i + offset + p] = (mod + l - r) % mod * irot % mod; + } + if (s + 1 != (1 << (len - 1))) { + irot *= info.irate2[Integer.numberOfTrailingZeros(~s)]; + irot %= mod; + } } - int x = Integer.numberOfTrailingZeros(~s); - inow = inow * sumIE[x] % mod; + len--; + } else { + // 4-base + int p = 1 << (h - len); + long irot = 1, iimag = info.iroot[2]; + for (int s = 0; s < (1 << (len - 2)); s++) { + long irot2 = irot * irot % mod; + long irot3 = irot2 * irot % mod; + int offset = s << (h - len + 2); + for (int i = 0; i < p; i++) { + long a0 = 1L * a[i + offset + 0 * p]; + long a1 = 1L * a[i + offset + 1 * p]; + long a2 = 1L * a[i + offset + 2 * p]; + long a3 = 1L * a[i + offset + 3 * p]; + + long a2na3iimag = 1L * (mod + a2 - a3) % mod * iimag % mod; + + a[i + offset] = (a0 + a1 + a2 + a3) % mod; + a[i + offset + 1 * p] = (a0 + (mod - a1) + a2na3iimag) % mod * irot % mod; + a[i + offset + 2 * p] = (a0 + a1 + (mod - a2) + (mod - a3)) % mod * irot2 % mod; + a[i + offset + 3 * p] = (a0 + (mod - a1) + (mod - a2na3iimag)) % mod * irot3 % mod; + } + if (s + 1 != (1 << (len - 2))) { + irot *= info.irate3[Integer.numberOfTrailingZeros(~s)]; + irot %= mod; + } + } + len -= 2; } } } @@ -193,26 +239,61 @@ private static void butterflyInv(long[] a, long[] sumIE, int mod) { * Inverse NTT. * * @param a Target array. - * @param sumE Pre-calculation table. + * @param g Primitive root of mod. * @param mod NTT Prime. */ - private static void butterfly(long[] a, long[] sumE, int mod) { + private static void butterfly(long[] a, int g, int mod) { int n = a.length; int h = ceilPow2(n); - for (int ph = 1; ph <= h; ph++) { - int w = 1 << (ph - 1), p = 1 << (h - ph); - long now = 1; - for (int s = 0; s < w; s++) { - int offset = s << (h - ph + 1); - for (int i = 0; i < p; i++) { - long l = a[i + offset]; - long r = a[i + offset + p] * now % mod; - a[i + offset] = (l + r) % mod; - a[i + offset + p] = (l - r + mod) % mod; + FftInfo info = new FftInfo(g, mod); + + int len = 0; // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed + while (len < h) { + if (h - len == 1) { + int p = 1 << (h - len - 1); + long rot = 1; + for (int s = 0; s < (1 << len); s++) { + int offset = s << (h - len); + for (int i = 0; i < p; i++) { + long l = a[i + offset]; + long r = a[i + offset + p] * rot % mod; + a[i + offset] = (l + r) % mod; + a[i + offset + p] = (l + mod - r) % mod; + } + if (s + 1 != (1 << len)) { + rot *= info.rate2[Integer.numberOfTrailingZeros(~s)]; + rot %= mod; + } + } + len++; + } else { + // 4-base + int p = 1 << (h - len - 2); + long rot = 1, imag = info.root[2]; + for (int s = 0; s < (1 << len); s++) { + long rot2 = rot * rot % mod; + long rot3 = rot2 * rot % mod; + int offset = s << (h - len); + for (int i = 0; i < p; i++) { + long mod2 = 1L * mod * mod; + long a0 = 1L * a[i + offset]; + long a1 = 1L * a[i + offset + p] * rot % mod; + long a2 = 1L * a[i + offset + 2 * p] * rot2 % mod; + long a3 = 1L * a[i + offset + 3 * p] * rot3 % mod; + long a1na3imag = 1L * (a1 + mod2 - a3) % mod * imag % mod; + long na2 = mod2 - a2; + a[i + offset] = (a0 + a2 + a1 + a3) % mod; + a[i + offset + 1 * p] = (a0 + a2 + (2 * mod2 - (a1 + a3))) % mod; + a[i + offset + 2 * p] = (a0 + na2 + a1na3imag) % mod; + a[i + offset + 3 * p] = (a0 + na2 + (mod2 - a1na3imag)) % mod; + } + if (s + 1 != (1 << len)) { + rot *= info.rate3[Integer.numberOfTrailingZeros(~s)]; + rot %= mod; + } } - int x = Integer.numberOfTrailingZeros(~s); - now = now * sumE[x] % mod; + len += 2; } } } @@ -241,15 +322,13 @@ public static long[] convolution(long[] a, long[] b, int mod) { } int g = primitiveRoot(mod); - long[] sume = sumE(mod, g); - long[] sumie = sumIE(mod, g); - butterfly(a, sume, mod); - butterfly(b, sume, mod); + butterfly(a, g, mod); + butterfly(b, g, mod); for (int i = 0; i < z; i++) { a[i] = a[i] * b[i] % mod; } - butterflyInv(a, sumie, mod); + butterflyInv(a, g, mod); a = java.util.Arrays.copyOf(a, n + m - 1); long iz = pow(z, mod - 2, mod); From d44d306f883596286b86129749f8953b4926ea30 Mon Sep 17 00:00:00 2001 From: Hiromi Ayase Date: Fri, 23 Jul 2021 03:31:06 +0900 Subject: [PATCH 48/48] remove vscode files --- .vscode/settings.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index d777ab6..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "java.project.sourcePaths": [ - "Convolution", - "ModInt" - ] -} \ No newline at end of file