結果
問題 | No.2277 Honest or Dishonest ? |
ユーザー | CoCo_Japan_pan |
提出日時 | 2023-04-21 23:30:46 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 59 ms / 2,000 ms |
コード長 | 9,910 bytes |
コンパイル時間 | 3,659 ms |
コンパイル使用メモリ | 232,072 KB |
実行使用メモリ | 16,528 KB |
最終ジャッジ日時 | 2024-11-15 05:34:27 |
合計ジャッジ時間 | 7,060 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,248 KB |
testcase_02 | AC | 2 ms
5,248 KB |
testcase_03 | AC | 42 ms
9,496 KB |
testcase_04 | AC | 49 ms
14,092 KB |
testcase_05 | AC | 28 ms
14,556 KB |
testcase_06 | AC | 29 ms
7,204 KB |
testcase_07 | AC | 27 ms
7,916 KB |
testcase_08 | AC | 30 ms
16,528 KB |
testcase_09 | AC | 35 ms
12,632 KB |
testcase_10 | AC | 19 ms
5,888 KB |
testcase_11 | AC | 11 ms
5,248 KB |
testcase_12 | AC | 15 ms
5,248 KB |
testcase_13 | AC | 34 ms
8,116 KB |
testcase_14 | AC | 19 ms
5,248 KB |
testcase_15 | AC | 25 ms
12,516 KB |
testcase_16 | AC | 27 ms
7,456 KB |
testcase_17 | AC | 14 ms
5,248 KB |
testcase_18 | AC | 48 ms
14,540 KB |
testcase_19 | AC | 48 ms
13,868 KB |
testcase_20 | AC | 36 ms
10,564 KB |
testcase_21 | AC | 23 ms
5,760 KB |
testcase_22 | AC | 31 ms
9,652 KB |
testcase_23 | AC | 29 ms
6,144 KB |
testcase_24 | AC | 30 ms
10,084 KB |
testcase_25 | AC | 41 ms
14,848 KB |
testcase_26 | AC | 25 ms
16,008 KB |
testcase_27 | AC | 15 ms
5,248 KB |
testcase_28 | AC | 23 ms
11,700 KB |
testcase_29 | AC | 33 ms
13,820 KB |
testcase_30 | AC | 17 ms
6,016 KB |
testcase_31 | AC | 30 ms
8,532 KB |
testcase_32 | AC | 30 ms
13,244 KB |
testcase_33 | AC | 44 ms
13,080 KB |
testcase_34 | AC | 40 ms
10,128 KB |
testcase_35 | AC | 15 ms
10,672 KB |
testcase_36 | AC | 26 ms
7,652 KB |
testcase_37 | AC | 33 ms
7,040 KB |
testcase_38 | AC | 9 ms
5,248 KB |
testcase_39 | AC | 12 ms
5,248 KB |
testcase_40 | AC | 13 ms
8,740 KB |
testcase_41 | AC | 42 ms
10,388 KB |
testcase_42 | AC | 32 ms
9,100 KB |
testcase_43 | AC | 58 ms
15,580 KB |
testcase_44 | AC | 59 ms
15,452 KB |
testcase_45 | AC | 58 ms
15,580 KB |
testcase_46 | AC | 59 ms
15,456 KB |
testcase_47 | AC | 58 ms
15,476 KB |
testcase_48 | AC | 58 ms
15,452 KB |
testcase_49 | AC | 58 ms
15,452 KB |
testcase_50 | AC | 58 ms
15,448 KB |
testcase_51 | AC | 59 ms
15,500 KB |
testcase_52 | AC | 57 ms
15,452 KB |
ソースコード
#line 2 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/template/procon.hpp" #ifndef DEBUG // 提出時にassertはオフ #ifndef NDEBUG #define NDEBUG #endif // 定数倍高速化 #pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #endif #include <bits/stdc++.h> using namespace std; using ll = long long; #define ALL(x) (x).begin(), (x).end() template <class T> using vec = vector<T>; template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); } template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); } template <class T> constexpr T INF = 1'000'000'000; template <> constexpr int INF<int> = 1'000'000'000; template <> constexpr ll INF<ll> = ll(INF<int>) * INF<int> * 2; #line 2 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/modint/modint_static.hpp" #line 2 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/modint/innermath_modint.hpp" #line 4 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/modint/innermath_modint.hpp" #ifdef _MSC_VER #include <intrin.h> #endif namespace innermath_modint{ using ll = long long; using ull = unsigned long long; using u128 = __uint128_t; // xのmodを[0, mod)で返す constexpr ll safe_mod(ll x, ll mod) { x %= mod; if (x < 0) x += mod; return x; } constexpr ll pow_mod_constexpr(ll x, ll n, ll mod) { if (mod == 1) return 0; ll ret = 1; ll beki = safe_mod(x, mod); while (n) { // LSBから順に見る if (n & 1) { ret = (ret * beki) % mod; } beki = (beki * beki) % mod; n >>= 1; } return ret; } // int型(2^32以下)の高速な素数判定 constexpr bool is_prime_constexpr(int n) { if (n <= 1) return false; if (n == 2 || n == 7 || n == 61) return true; if (n % 2 == 0) return false; // ミラーラビン判定 int型ならa={2,7,61}で十分 constexpr ll bases[] = {2, 7, 61}; // n-1 = 2^r * d ll d = n - 1; while (d % 2 == 0) d >>= 1; // 素数modは1の平方根として非自明な解を持たない // つまり非自明な解がある→合成数 for (ll a : bases) { ll t = d; ll y = pow_mod_constexpr(a, t, n); // yが1またはn-1になれば抜ける while (t != n - 1 && y != 1 && y != n - 1) { y = (y * y) % n; t <<= 1; } // 1の平方根として1と-1以外の解(非自明な解)が存在 if (y != n - 1 && t % 2 == 0) { return false; } } return true; } // 拡張ユークリッドの互除法 g = gcd(a,b)と、ax = g (mod b)なる0 <= x < // b/gのペアを返す constexpr std::pair<ll, ll> inv_gcd(ll a, ll b) { a = safe_mod(a, b); // aがbの倍数 if (a == 0) return {b, 0}; // 以下 0 <= a < b // [1] s - m0 * a = 0 (mod b) // [2] t - m1 * a = 0 (mod b) // [3] s * |m1| + t * |m0| <= b ll s = b, t = a; ll m0 = 0, m1 = 1; while (t) { // s → s mod t // m0 → m0 - m1 * (s / t) ll u = s / t; s -= t * u; m0 -= m1 * u; std::swap(s, t); std::swap(m0, m1); } // s = gcd(a, b) // 終了の直前のステップにおいて // [1] k * s - m0 * a = 0 (mod b) // [2] s - m1 * a = 0 (mod b) // [3] (k * s) * |m1| + s * |m0| <= b // |m0| < b / s if (m0 < 0) m0 += b / s; return {s, m0}; } // barret reduction 掛け算のmodの定数倍高速化(modが定数でない場合に使用) struct barretReduction { public: explicit barretReduction(uint _mod) : mod(_mod), imod((ull)(-1) / mod + 1) {} // unsignedの場合、負で巡回する uint get_mod() const { return mod; } uint mul(int a, int b) const { ull z = a; z *= b; #ifdef _MSC_VER ull x; _umul128(z, imod, &x) #else // x = z / mod またはその +1 // 割り算をビットシフトにすることで高速化 ull x = (ull)(((u128)z * imod) >> 64); #endif // z - x * mod = z % mod - mod の場合、uintなので 2^32 - (mod - // z % mod) つまりmodを足せば 2^32 + z % // modとなり、求めるmodになる uint v = (uint)(z - x * mod); if (v >= mod) v += mod; return v; } private: uint mod; ull imod; // ceil(2^64 / mod) }; } #line 5 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/modint/modint_static.hpp" template <const int MOD> struct modint_static { using ll = long long; public: constexpr modint_static(ll x = 0) noexcept : value(x % MOD) { if (value < 0) value += MOD; } constexpr int get_mod() const noexcept { return MOD; } constexpr ll val() const noexcept { return value; } constexpr modint_static operator-() const noexcept { return modint_static(-value); } constexpr modint_static& operator++() noexcept { ++value; if(value == MOD) value = 0; return *this; } constexpr modint_static& operator--() noexcept { if(value == 0) value = MOD; --value; return *this; } constexpr modint_static operator++(int) noexcept { modint_static cpy(*this); ++(*this); return cpy; } constexpr modint_static operator--(int) noexcept { modint_static cpy(*this); --(*this); return cpy; } constexpr modint_static& operator+=(const modint_static& rhs) noexcept { value += rhs.value; if (value >= MOD) value -= MOD; return *this; } constexpr modint_static& operator-=(const modint_static& rhs) noexcept { value += (MOD - rhs.value); if (value >= MOD) value -= MOD; return *this; } constexpr modint_static& operator*=(const modint_static& rhs) noexcept { (value *= rhs.value) %= MOD; // 定数だとコンパイラ最適化がかかる return *this; } constexpr modint_static operator+(const modint_static& rhs) const noexcept { modint_static cpy(*this); return cpy += rhs; } constexpr modint_static operator-(const modint_static& rhs) const noexcept { modint_static cpy(*this); return cpy -= rhs; } constexpr modint_static operator*(const modint_static& rhs) const noexcept { modint_static cpy(*this); return cpy *= rhs; } constexpr modint_static pow(ll beki) const noexcept { modint_static curbekimod(*this); modint_static ret(1); while (beki > 0) { if (beki & 1) ret *= curbekimod; curbekimod *= curbekimod; beki >>= 1; } return ret; } // valueの逆元を求める constexpr modint_static inv() const noexcept { // 拡張ユークリッドの互除法 auto [gcd_value_mod, inv_value] = innermath_modint::inv_gcd(value, MOD); assert(gcd_value_mod == 1); return modint_static(inv_value); } constexpr modint_static& operator/=(const modint_static& rhs) noexcept { return (*this) *= rhs.inv(); } constexpr modint_static operator/(const modint_static& rhs) const noexcept { modint_static cpy(*this); return cpy /= rhs; } private: ll value; }; using mint998244353 = modint_static<998244353>; using mint1000000007 = modint_static<1000000007>; #line 3 "main.cpp" #include <atcoder/dsu> using namespace atcoder; using mint = mint998244353; bool ng = false; void dfs(const vec<vec<int>> &graph, vec<int> &checked, int start, int num) { for(int next : graph[start]) { if(checked[next] == -num) { ng = true; break; } if(checked[next] == num) continue; checked[next] = num; dfs(graph, checked, next, -num); } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int N, Q; cin >> N >> Q; dsu mydsu(N); vec<int> A(Q), B(Q), C(Q); for(int i = 0; i < Q; i++) { cin >> A[i] >> B[i] >> C[i]; --A[i]; --B[i]; mydsu.merge(A[i], B[i]); } vec<vec<int>> groups = mydsu.groups(); // ci=0のところは縮退 dsu syukutaiGraphDSU(N); for(int i = 0; i < Q; i++) { if(C[i] == 0) { syukutaiGraphDSU.merge(A[i], B[i]); } } vec<vec<int>> syukutaiGraph = syukutaiGraphDSU.groups(); // 各頂点が縮退グラフではどこのindexかを返す vec<int> whichSyukutai(N); for(int i = 0; i < (int)syukutaiGraph.size(); i++) { for(int num : syukutaiGraph[i]) { whichSyukutai[num] = i; } } vec<vec<int>> graph(syukutaiGraph.size()); for(int i = 0; i < Q; i++) { if(C[i] == 1) { graph[whichSyukutai[A[i]]].push_back(whichSyukutai[B[i]]); graph[whichSyukutai[B[i]]].push_back(whichSyukutai[A[i]]); } } // 矛盾がないかチェック // 奇数閉路があったらアウト // つまり二部グラフならOK vec<int> checked(syukutaiGraph.size()); for(int i = 0; i < (int)syukutaiGraph.size(); i++) { if(checked[i] != 0) continue; int num = 1; checked[i] = num; num *= -1; dfs(graph, checked, i, num); if(ng) { cout << 0 << "\n"; return 0; } } cout << mint(2).pow(groups.size()).val() << "\n"; }