結果
問題 |
No.274 The Wall
|
ユーザー |
![]() |
提出日時 | 2020-10-17 13:51:24 |
言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 383 ms / 2,000 ms |
コード長 | 3,998 bytes |
コンパイル時間 | 1,233 ms |
コンパイル使用メモリ | 103,124 KB |
実行使用メモリ | 148,736 KB |
最終ジャッジ日時 | 2025-03-17 19:08:12 |
合計ジャッジ時間 | 3,281 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 23 |
ソースコード
#include <iostream> #include <iomanip> #include <utility> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <cmath> #include <cstring> #include <map> #include <climits> #include <bitset> #include <ctime> using ll = long long; const ll INF = 1 << 29; class TwoSAT { public: TwoSAT(const int literal_count) : V(literal_count), connection(2 * V), reversedConnection(2 * V), cmp(2 * V, -1){} void AddClosure(int x, int y) { AddEdge(x, y); // !x, !y が inout 似ない場合はこっち // AddEdge((x + V) % (2 * V), y); // !x -> y // AddEdge((y + V) % (2 * V), x); // !y -> x } std::pair<bool, std::vector<int>> Satisfy() { SCC(); std::vector<int> ans(V); for(auto i = 0; i < V; i++) { // x -> !x 成り立つ = 同じグラフ上にあるとき充足不可能(矛盾) if(cmp[i] == cmp[V + i]) return std::make_pair(false, ans); // そうでなければ充足可能な変数の組み合わせが存在する. // x が !x のトポロジカル順序より後なら x は真 // ( dfs の探索順で先に判明した組み合わせの値を解として返す ) ans[i] = (cmp[V + i] < cmp[i]); } return std::make_pair(true, ans); } private: const int V; std::vector<std::vector<int>> connection, reversedConnection; std::vector<int> ps, cmp; void AddEdge(int from, int to) { connection[from].push_back(to); reversedConnection[to].push_back(from); } void DFS(int u) { cmp[u] = 0; for(auto v : connection[u]) { if(cmp[v] == -1) DFS(v); } ps.push_back(u); } void RDFS(int u, int k) { cmp[u] = k; for(auto v : reversedConnection[u]) { if(cmp[v] == -1) RDFS(v, k); } } void SCC() { for(auto i = 0; i < 2 * V; ++i) { if(cmp[i] == -1) DFS(i); } fill(cmp.begin(), cmp.end(), -1); int k = 0; for(auto i = 2 * V - 1; 0 <= i; --i) { if(cmp[ps[i]] == -1) RDFS(ps[i], k++); } } }; int main() { int N, M; std::cin >> N >> M; TwoSAT sat(N); std::vector<int> L(N); std::vector<int> R(N); std::vector<int> revL(N); std::vector<int> revR(N); for (auto i=0; i<N; ++i) { std::cin >> L[i] >> R[i]; revR[i] = M - L[i] - 1; revL[i] = M - R[i] - 1; } for (auto i=0; i<N; i++) { for (auto j=0; j<i; j++) { // B が A に含まれてる -> どっちか回転 (B && !A) or (!B && A) if(L[i] <= R[j] && L[j] <= R[i]) { sat.AddClosure(i, j + N); sat.AddClosure(i + N, j); } // 反転したB が A に含まれてる -> Bを回転しない or Aを回転 (!B && !A) or (B && A) if(L[i] <= revR[j] && revL[j] <= R[i]) { sat.AddClosure(i, j); sat.AddClosure(i + N, j + i); } // B が 反転したA に含まれてる -> Bを回転 or Aを回転しない : (!A && !B) or (A && B) if(revL[i] <= R[j] && L[j] <= revR[i]) { sat.AddClosure(j + N, i + N); sat.AddClosure(j, i); } // 反転したB が 反転したA に含まれてる -> どっちか回転 : (!A && B) or (A && !B) if(revL[i] <= revR[j] && revL[j] <= revR[i]) { sat.AddClosure(j + N, i); sat.AddClosure(j, i + N); } } } auto result = sat.Satisfy(); if (!result.first) std::cout << "NO" << std::endl; else std::cout << "YES" << std::endl; }