Min of Restricted Sum
AtCoder Beginner Contest 396 E
문제
난이도: 1379
풀이
정수 의 번째 비트를 라 합시다.
그렇다면 주어진 조건 를 인 조건 31개로 나눌 수 있습니다.
서로 다른 위치의 비트는 xor 연산에서 서로에게 영향을 주지 않기 때문입니다.
이제 문제를 어떤 에 대해 를 몇 개 골라 번째 비트를 최소한으로 켜서 xor 결과가 와 일치하도록 만드는 문제를 각각 푸는 것으로 나눌 수 있습니다.
주어진 조건을 와 를 가중치 인 간선으로 잇는 것으로 생각합시다.
만들어진 그래프에서 어떤 연결 요소 에서 임의의 정점 하나를 뽑아 이라 합시다.
만약 의 번째 비트가 결정된다면 같은 연결 요소에 속한 다른 모든 정점의 번째 비트도 결정됩니다.
이는 트리 동적 계획법으로 에 구할 수 있습니다. 의 번째 비트가 인 경우와 인 경우를 각각 계산한 다음 더 작은 방법을 선택하면 됩니다.
이를 에 대해 모두 수행하면 답을 구할 수 있습니다.
코드
#include <bits/stdc++.h>
using namespace std;
vector<pair<int, int>> adj[202020];
bool visited[202020];
int root[202020], sz[202020];
void preprocessGraph(int cur) {
visited[cur] = true;
int r = root[cur];
sz[r]++;
for (auto [child, _] : adj[cur]) {
if (visited[child]) continue;
root[child] = r;
preprocessGraph(child);
}
}
bool impossible = false;
bool isSet[202020];
int setCnt[202020];
void calcSetCnt(int b, int cur) {
visited[cur] = true;
setCnt[root[cur]] += isSet[cur];
for (auto [child, z] : adj[cur]) {
if (visited[child]) {
if ((isSet[cur] ^ isSet[child]) != ((z >> b) & 1))
impossible = true;
continue;
}
isSet[child] = isSet[cur] ^ ((z >> b) & 1);
calcSetCnt(b, child);
}
}
int A[202020];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, M;
cin >> N >> M;
for (int i = 1; i <= M; i++) {
int X, Y, Z;
cin >> X >> Y >> Z;
adj[X].emplace_back(Y, Z);
adj[Y].emplace_back(X, Z);
}
for (int v = 1; v <= N; v++) {
if (visited[v]) continue;
root[v] = v;
preprocessGraph(v);
}
for (int b = 0; b < 31; b++) {
fill(visited + 1, visited + N + 1, false);
fill(isSet + 1, isSet + N + 1, false);
fill(setCnt + 1, setCnt + N + 1, 0);
for (int v = 1; v <= N; v++) {
if (not visited[v]) {
calcSetCnt(b, v);
if (impossible) {
cout << -1;
return 0;
}
}
int r = root[v];
bool invert = setCnt[r] > sz[r] - setCnt[r];
A[v] |= (isSet[v] ^ invert) << b;
}
}
for (int i = 1; i <= N; i++) cout << A[i] << ' ';
return 0;
}댓글
이름과 이메일을 입력해 댓글을 남겨주세요.