結果
問題 |
No.1955 Not Prime
|
ユーザー |
![]() |
提出日時 | 2025-03-16 02:30:04 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 122 ms / 2,000 ms |
コード長 | 3,546 bytes |
コンパイル時間 | 4,681 ms |
コンパイル使用メモリ | 299,496 KB |
実行使用メモリ | 31,608 KB |
最終ジャッジ日時 | 2025-03-16 02:30:11 |
合計ジャッジ時間 | 6,210 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 26 |
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; vector<bool> prime_table; void erat(ll N){ prime_table.resize(N+1, 1); prime_table[0] = 0; prime_table[1] = 0; for (ll i=2; i*i<=N; i++){ if (prime_table[i]){ for (ll j=i*2; j <= N; j+=i){ prime_table[j] = 0; } } } } vector<vector<int>> scc(const vector<vector<int>> &E){ int N = E.size(); vector<vector<int>> rev(N), components; vector<bool> vst(N); vector<int> order; for (int i=0; i<N; i++){ for (auto x : E[i]) rev[x].push_back(i); } auto dfs1=[&](auto self, int from)->void{ vst[from] = 1; for (int to : E[from]){ if (vst[to]) continue; self(self, to); } order.push_back(from); }; for (int i=0; i<N; i++) if (!vst[i]) dfs1(dfs1, i); reverse(order.begin(), order.end()); fill(vst.begin(), vst.end(), 0); auto dfs2=[&](auto self, int from, vector<int> &comp)->void{ vst[from] = 1; comp.push_back(from); for (int to : rev[from]){ if (vst[to]) continue; self(self, to, comp); } }; for (auto v : order){ if (!vst[v]){ vector<int> comp; dfs2(dfs2, v, comp); reverse(comp.begin(), comp.end()); components.push_back(comp); } } return components; } //clause = [i1, i2, f1, f2] // x_i1 = f1 or x_i2 = f2 (f1 = 0なら !x_i1)のような2個のリテラルからなる節の論理積がtrueとなる割り当て(x1, x2, ..., xN)を求める。存在しないなら空の配列を返す。 vector<bool> two_sat(int N, const vector<tuple<int, int, bool, bool>> &clause){ vector<vector<int>> E(N*2), sc; for (auto [i1, i2, f1, f2] : clause){ E[i1 * 2 + !f1].push_back(i2 * 2 + f2); E[i2 * 2 + !f2].push_back(i1 * 2 + f1); } sc = scc(E); int M = sc.size(); vector<bool> res(N); vector<int> id(N*2); for (int i=0; i<M; i++){ for (auto v : sc[i]) id[v] = i; } for (int i=0; i<N; i++){ if (id[i*2] == id[i*2+1]) return {}; res[i] = (id[i*2] < id[i*2+1]); } return res; }; int main(){ cin.tie(nullptr); ios_base::sync_with_stdio(false); /* x_i = 1 (iをSに振り分ける。) x_i = 0 (iをTに振り分ける。) A_i -> 2*i, B_i -> 2*i+1 (1) z_{i*2} or z_{i*2+1} (どちらかがS) (2) !z_{i*2} or !z_{i*2+1} (どちらかがT) (3) if (prime(i*2, j*2+1)) !z_{i*2} or z_{j*2+1} = !(z_{i*2} and !z_{j*2+1}) (SとTが素数にならない) */ erat(999999); int N; cin >> N; vector<int> a(N), b(N); vector<tuple<int, int, bool, bool>> v; for (int i=0; i<N; i++) cin >> a[i] >> b[i]; for (int i=0; i<N; i++){ v.push_back({i*2, i*2+1, 1, 1}); v.push_back({i*2, i*2+1, 0, 0}); } auto f=[&](int x, int y)->bool{ int res = stoi(to_string(x) + to_string(y)); return prime_table[res]; }; for (int i=0; i<N; i++){ for (int j=0; j<N; j++){ if (f(a[i], a[j])) v.push_back({i*2, j*2, 0, 1}); if (f(b[i], b[j])) v.push_back({i*2+1, j*2+1, 0, 1}); if (f(a[i], b[j])) v.push_back({i*2, j*2+1, 0, 1}); if (f(b[i], a[j])) v.push_back({i*2+1, j*2, 0, 1}); } } vector<bool> ans = two_sat(N*2, v); cout << (ans.size() == 0 ? "No" : "Yes") << endl; return 0; }