結果
| 問題 |
No.1773 Love Triangle
|
| コンテスト | |
| ユーザー |
hitonanode
|
| 提出日時 | 2021-12-03 00:37:38 |
| 言語 | C++17(clang) (17.0.6 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 22 ms / 2,000 ms |
| コード長 | 4,695 bytes |
| コンパイル時間 | 3,556 ms |
| コンパイル使用メモリ | 147,552 KB |
| 実行使用メモリ | 6,944 KB |
| 最終ジャッジ日時 | 2024-07-05 03:00:16 |
| 合計ジャッジ時間 | 7,359 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 90 |
ソースコード
// O(n^2 + nm) solution by black box linear algebra
// https://yukicoder.me/wiki/black_box_linear_algebra
#include <algorithm>
#include <cassert>
#include <iostream>
#include <random>
#include <tuple>
#include <vector>
using namespace std;
mt19937 mt(530629);
// https://github.com/hitonanode/cplib-cpp/blob/master/formal_power_series/linear_recurrence.hpp
// Berlekamp–Massey algorithm
// https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm
// Complexity: O(N^2)
// input: S = sequence from field K
// return: L = degree of minimal polynomial,
// C_reversed = monic min. polynomial (size = L + 1, reversed order, C_reversed[0] = 1))
// Formula: convolve(S, C_reversed)[i] = 0 for i >= L
// Example:
// - [1, 2, 4, 8, 16] -> (1, [1, -2])
// - [1, 1, 2, 3, 5, 8] -> (2, [1, -1, -1])
// - [0, 0, 0, 0, 1] -> (5, [1, 0, 0, 0, 0, 998244352]) (mod 998244353)
// - [] -> (0, [1])
// - [0, 0, 0] -> (0, [1])
// - [-2] -> (1, [1, 2])
template <typename Tfield> std::pair<int, std::vector<Tfield>> find_linear_recurrence(const std::vector<Tfield> &S) {
int N = S.size();
using poly = std::vector<Tfield>;
poly C_reversed{1}, B{1};
int L = 0, m = 1;
Tfield b = 1;
// adjust: C(x) <- C(x) - (d / b) x^m B(x)
auto adjust = [](poly C, const poly &B, Tfield d, Tfield b, int m) -> poly {
C.resize(std::max(C.size(), B.size() + m));
Tfield a = d / b;
for (unsigned i = 0; i < B.size(); i++) C[i + m] -= a * B[i];
return C;
};
for (int n = 0; n < N; n++) {
Tfield d = S[n];
for (int i = 1; i <= L; i++) d += C_reversed[i] * S[n - i];
if (d == 0)
m++;
else if (2 * L <= n) {
poly T = C_reversed;
C_reversed = adjust(C_reversed, B, d, b, m);
L = n + 1 - L;
B = T;
b = d;
m = 1;
} else
C_reversed = adjust(C_reversed, B, d, b, m++);
}
return std::make_pair(L, C_reversed);
}
// https://github.com/hitonanode/cplib-cpp/blob/master/linear_algebra_matrix/blackbox_algorithm.hpp
template <typename ModInt> std::vector<ModInt> gen_random_vector(int len) {
static std::uniform_int_distribution<int> rnd(1, ModInt::mod() - 1);
std::vector<ModInt> ret(len);
for (auto &x : ret) x = rnd(mt);
return ret;
};
// https://github.com/hitonanode/cplib-cpp/blob/master/linear_algebra_matrix/blackbox_matrices.hpp
// Sparse matrix
template <typename Tp> struct sparse_matrix {
int H, W;
std::vector<std::vector<std::pair<int, Tp>>> vals;
sparse_matrix(int H = 0, int W = 0) : H(H), W(W), vals(H) {}
int height() const { return H; }
int width() const { return W; }
void add_element(int i, int j, Tp val) {
assert(i >= 0 and i < H);
assert(j >= 0 and i < W);
vals[i].emplace_back(j, val);
}
std::vector<Tp> prod(const std::vector<Tp> &vec) const {
assert(W == int(vec.size()));
std::vector<Tp> ret(H);
for (int i = 0; i < H; i++) {
for (const auto &p : vals[i]) ret[i] += p.second * vec[p.first];
}
return ret;
}
};
template <class Matrix, class Tp> int blackbox_rank(const Matrix &M) {
assert(M.height() == M.width());
const int N = M.height();
std::vector<Tp> b = gen_random_vector<Tp>(N), u = gen_random_vector<Tp>(N), D = gen_random_vector<Tp>(N);
std::vector<Tp> uMDib(2 * N);
for (int i = 0; i < 2 * N; i++) {
uMDib[i] = std::inner_product(u.begin(), u.end(), b.begin(), Tp(0));
for (int j = 0; j < N; j++) b[j] *= D[j];
b = M.prod(b);
}
return find_linear_recurrence<Tp>(uMDib).first - 1;
}
#include <atcoder/modint>
using mint = atcoder::modint1000000007;
uniform_int_distribution<int> rndgen(0, mint::mod());
int solve(int r, const vector<tuple<int, int, int>> &uvws) {
const int m = uvws.size();
sparse_matrix<mint> mat(r, r);
for (int i = 0; i < m; ++i) {
auto [u, v, w] = uvws[i];
mint x = rndgen(mt);
mat.add_element(u, v, x);
mat.add_element(v, w, x);
mat.add_element(w, u, x);
mat.add_element(v, u, -x);
mat.add_element(w, v, -x);
mat.add_element(u, w, -x);
}
int rank = blackbox_rank<sparse_matrix<mint>, mint>(mat);
return rank / 2;
}
int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);
int N, M;
cin >> N >> M;
vector<tuple<int, int, int>> uvws;
while (M--) {
int u, v, w;
cin >> u >> v >> w;
u--, v--, w--;
uvws.emplace_back(u, v, w);
}
cout << solve(N, uvws) << '\n';
}
hitonanode