結果

問題 No.1502 Many Simple Additions
ユーザー 👑 rin204
提出日時 2023-12-29 00:09:45
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 62 ms / 2,000 ms
コード長 12,547 bytes
コンパイル時間 3,495 ms
コンパイル使用メモリ 264,224 KB
実行使用メモリ 16,196 KB
最終ジャッジ日時 2024-09-27 15:56:11
合計ジャッジ時間 6,836 ms
ジャッジサーバーID
(参考情報)
judge4 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 5
other AC * 39
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

#include <bits/stdc++.h>
using namespace std;
#include <bits/stdc++.h>
template <typename T = long long>
struct UnionFindSumConstraints {
int n;
std::vector<int> par;
int group;
// x A[i] = (pm[i] ? 1 : -1) x + B[i]
std::vector<bool> pm;
std::vector<T> B;
// unique:
// X2: 2
std::vector<bool> unique;
std::vector<T> X2;
UnionFindSumConstraints(int n) : n(n), group(n) {
par.assign(n, -1);
pm.assign(n, true);
B.assign(n, T(0));
unique.assign(n, false);
X2.assign(n, T(0));
}
int find(int x) {
if (par[x] < 0) return x;
int p = par[x];
if (par[p] < 0) return p;
find(par[x]);
if (pm[x]) {
pm[x] = pm[p];
B[x] += B[p];
} else {
pm[x] = !pm[p];
B[x] -= B[p];
}
par[x] = par[p];
return par[x];
}
bool can_unite(int x, int y, T z) {
// A[x] + A[y] == z
int xp = find(x);
int yp = find(y);
if (xp == yp) {
int p = xp;
if (pm[x] != pm[y]) {
return B[x] + B[y] == z;
} else {
if (unique[p]) {
if (pm[x]) {
return B[x] + B[y] + X2[p] == z;
} else {
return B[x] + B[y] - X2[p] == z;
}
} else {
unique[p] = true;
if (pm[x]) {
X2[p] = z - B[x] - B[y];
} else {
X2[p] = B[x] + B[y] - z;
}
return true;
}
}
} else {
if (!unique[xp] or !unique[yp]) {
return true;
}
T x2 = (pm[x] ? X2[xp] : -X2[xp]) + B[x] * 2;
T y2 = (pm[y] ? X2[yp] : -X2[yp]) + B[y] * 2;
return x2 + y2 == 2 * z;
}
}
bool unite(int x, int y, T z) {
// A[x] + A[y] == z
assert(can_unite(x, y, z));
int xp = find(x);
int yp = find(y);
if (xp == yp) {
int p = xp;
if (pm[x] != pm[y]) {
assert(B[x] + B[y] == z);
} else {
if (!unique[p]) {
unique[p] = true;
if (pm[x]) {
X2[p] = z - B[x] - B[y];
} else {
X2[p] = B[x] + B[y] - z;
}
}
}
return false;
}
if (par[xp] > par[yp]) {
std::swap(x, y);
std::swap(xp, yp);
}
group--;
par[xp] += par[yp];
par[yp] = xp;
T tmp = z - B[x] - B[y];
B[yp] = pm[y] ? tmp : -tmp;
pm[yp] = pm[x] ^ pm[y];
if (!unique[xp] and unique[yp]) {
T tmp = X2[yp] - 2 * B[yp];
X2[xp] = (pm[yp] ? tmp : -tmp);
unique[xp] = true;
}
return true;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return -par[find(x)];
}
std::vector<int> roots() {
std::vector<int> ret;
for (int i = 0; i < n; i++) {
if (i == find(i)) ret.push_back(i);
}
return ret;
}
bool isroot(int x) {
return x == find(x);
}
};
template <int MOD>
struct Modint {
int x;
Modint() : x(0) {}
Modint(int64_t y) {
if (y >= 0)
x = y % MOD;
else
x = (y % MOD + MOD) % MOD;
}
Modint &operator+=(const Modint &p) {
x += p.x;
if (x >= MOD) x -= MOD;
return *this;
}
Modint &operator-=(const Modint &p) {
x -= p.x;
if (x < 0) x += MOD;
return *this;
}
Modint &operator*=(const Modint &p) {
x = int(1LL * x * p.x % MOD);
return *this;
}
Modint &operator/=(const Modint &p) {
*this *= p.inverse();
return *this;
}
Modint &operator%=(const Modint &p) {
assert(p.x == 0);
return *this;
}
Modint operator-() const {
return Modint(-x);
}
Modint &operator++() {
x++;
if (x == MOD) x = 0;
return *this;
}
Modint &operator--() {
if (x == 0) x = MOD;
x--;
return *this;
}
Modint operator++(int) {
Modint result = *this;
++*this;
return result;
}
Modint operator--(int) {
Modint result = *this;
--*this;
return result;
}
friend Modint operator+(const Modint &lhs, const Modint &rhs) {
return Modint(lhs) += rhs;
}
friend Modint operator-(const Modint &lhs, const Modint &rhs) {
return Modint(lhs) -= rhs;
}
friend Modint operator*(const Modint &lhs, const Modint &rhs) {
return Modint(lhs) *= rhs;
}
friend Modint operator/(const Modint &lhs, const Modint &rhs) {
return Modint(lhs) /= rhs;
}
friend Modint operator%(const Modint &lhs, const Modint &rhs) {
assert(rhs.x == 0);
return Modint(lhs);
}
bool operator==(const Modint &p) const {
return x == p.x;
}
bool operator!=(const Modint &p) const {
return x != p.x;
}
bool operator<(const Modint &rhs) const {
return x < rhs.x;
}
bool operator<=(const Modint &rhs) const {
return x <= rhs.x;
}
bool operator>(const Modint &rhs) const {
return x > rhs.x;
}
bool operator>=(const Modint &rhs) const {
return x >= rhs.x;
}
Modint inverse() const {
int a = x, b = MOD, u = 1, v = 0, t;
while (b > 0) {
t = a / b;
a -= t * b;
u -= t * v;
std::swap(a, b);
std::swap(u, v);
}
return Modint(u);
}
Modint pow(int64_t k) const {
Modint ret(1);
Modint y(x);
while (k > 0) {
if (k & 1) ret *= y;
y *= y;
k >>= 1;
}
return ret;
}
friend std::ostream &operator<<(std::ostream &os, const Modint &p) {
return os << p.x;
}
friend std::istream &operator>>(std::istream &is, Modint &p) {
int64_t y;
is >> y;
p = Modint<MOD>(y);
return (is);
}
static int get_mod() {
return MOD;
}
};
struct Arbitrary_Modint {
int x;
static int MOD;
static void set_mod(int mod) {
MOD = mod;
}
Arbitrary_Modint() : x(0) {}
Arbitrary_Modint(int64_t y) {
if (y >= 0)
x = y % MOD;
else
x = (y % MOD + MOD) % MOD;
}
Arbitrary_Modint &operator+=(const Arbitrary_Modint &p) {
x += p.x;
if (x >= MOD) x -= MOD;
return *this;
}
Arbitrary_Modint &operator-=(const Arbitrary_Modint &p) {
x -= p.x;
if (x < 0) x += MOD;
return *this;
}
Arbitrary_Modint &operator*=(const Arbitrary_Modint &p) {
x = int(1LL * x * p.x % MOD);
return *this;
}
Arbitrary_Modint &operator/=(const Arbitrary_Modint &p) {
*this *= p.inverse();
return *this;
}
Arbitrary_Modint &operator%=(const Arbitrary_Modint &p) {
assert(p.x == 0);
return *this;
}
Arbitrary_Modint operator-() const {
return Arbitrary_Modint(-x);
}
Arbitrary_Modint &operator++() {
x++;
if (x == MOD) x = 0;
return *this;
}
Arbitrary_Modint &operator--() {
if (x == 0) x = MOD;
x--;
return *this;
}
Arbitrary_Modint operator++(int) {
Arbitrary_Modint result = *this;
++*this;
return result;
}
Arbitrary_Modint operator--(int) {
Arbitrary_Modint result = *this;
--*this;
return result;
}
friend Arbitrary_Modint operator+(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) {
return Arbitrary_Modint(lhs) += rhs;
}
friend Arbitrary_Modint operator-(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) {
return Arbitrary_Modint(lhs) -= rhs;
}
friend Arbitrary_Modint operator*(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) {
return Arbitrary_Modint(lhs) *= rhs;
}
friend Arbitrary_Modint operator/(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) {
return Arbitrary_Modint(lhs) /= rhs;
}
friend Arbitrary_Modint operator%(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) {
assert(rhs.x == 0);
return Arbitrary_Modint(lhs);
}
bool operator==(const Arbitrary_Modint &p) const {
return x == p.x;
}
bool operator!=(const Arbitrary_Modint &p) const {
return x != p.x;
}
bool operator<(const Arbitrary_Modint &rhs) {
return x < rhs.x;
}
bool operator<=(const Arbitrary_Modint &rhs) {
return x <= rhs.x;
}
bool operator>(const Arbitrary_Modint &rhs) {
return x > rhs.x;
}
bool operator>=(const Arbitrary_Modint &rhs) {
return x >= rhs.x;
}
Arbitrary_Modint inverse() const {
int a = x, b = MOD, u = 1, v = 0, t;
while (b > 0) {
t = a / b;
a -= t * b;
u -= t * v;
std::swap(a, b);
std::swap(u, v);
}
return Arbitrary_Modint(u);
}
Arbitrary_Modint pow(int64_t k) const {
Arbitrary_Modint ret(1);
Arbitrary_Modint y(x);
while (k > 0) {
if (k & 1) ret *= y;
y *= y;
k >>= 1;
}
return ret;
}
friend std::ostream &operator<<(std::ostream &os, const Arbitrary_Modint &p) {
return os << p.x;
}
friend std::istream &operator>>(std::istream &is, Arbitrary_Modint &p) {
int64_t y;
is >> y;
p = Arbitrary_Modint(y);
return (is);
}
static int get_mod() {
return MOD;
}
};
int Arbitrary_Modint::MOD = 998244353;
using modint9 = Modint<998244353>;
using modint1 = Modint<1000000007>;
using modint = Arbitrary_Modint;
using mint = modint1;
void solve() {
int n, m;
long long k;
cin >> n >> m >> k;
UnionFindSumConstraints UF(n);
for (int i = 0; i < m; i++) {
int x, y;
long long z;
cin >> x >> y >> z;
x--;
y--;
if (!UF.can_unite(x, y, z)) {
cout << 0 << endl;
return;
}
UF.unite(x, y, z);
}
const long long inf = 1LL << 60;
vector<vector<long long>> plus(n, {inf, -inf}), minus(n, {inf, -inf});
for (int i = 0; i < n; i++) {
int p = UF.find(i);
if (UF.unique[p] and UF.X2[p] % 2 == 1) {
cout << 0 << endl;
return;
}
if (UF.pm[i]) {
plus[p][0] = min(plus[p][0], UF.B[i]);
plus[p][1] = max(plus[p][1], UF.B[i]);
} else {
minus[p][0] = min(minus[p][0], UF.B[i]);
minus[p][1] = max(minus[p][1], UF.B[i]);
}
}
auto f = [&](long long k) -> mint {
mint ret = 1;
for (int i = 0; i < n; i++) {
if (!UF.isroot(i)) {
continue;
}
if (UF.size(i) == 1) {
ret *= k;
continue;
}
long long lp = 1 - plus[i][0];
long long rp = k - plus[i][1];
long long lm = minus[i][1] - k;
long long rm = minus[i][0] - 1;
if (rp < lp or rm < lm) {
return 0;
}
if (rp < lm or rm < lp) {
return 0;
}
long long l = max(lp, lm);
long long r = min(rp, rm);
if (UF.unique[i]) {
if (UF.X2[i] < 2 * l or 2 * r < UF.X2[i]) {
return 0;
}
} else {
ret *= r - l + 1;
}
}
return ret;
};
mint ans = f(k) - f(k - 1);
cout << ans << endl;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
// cout << fixed << setprecision(12);
int t;
t = 1;
// cin >> t;
while (t--) solve();
return 0;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0