結果
| 問題 |
No.1955 Not Prime
|
| コンテスト | |
| ユーザー |
srjywrdnprkt
|
| 提出日時 | 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;
}
srjywrdnprkt