코드포스 1515A Phoenix and Gold
문제
서로 다른 무게의 금덩이 N개를 저울에 하나씩 올린다. 그런데 저울은 올린 무게의 누적 합이 정확히 x가 되는 순간 폭발한다. 누적 합이 한 번도 x가 되지 않도록 올리는 순서를 찾으면 된다.
- 입력: 1번째 줄에 테스트케이스 수
t. 각 케이스마다n x, 그리고 금덩이 무게w_1 … w_n. - 출력: 가능하면
YES와 한 가지 순서, 불가능하면NO. - 제한:
t ≤ 1000,1 ≤ n ≤ 100,1 ≤ x ≤ 10,000.
접근
먼저 명백한 불가능 케이스. 전체 합이 x와 같으면 마지막에 다 올렸을 때 무조건 x가 되니 NO다. 어떤 순서로도 피할 수 없다.
그 외에는 정렬해두고 앞에서부터 누적 합을 쌓는다. 쌓다가 누적 합이 x가 되는 순간이 있으면, 그 원소를 더 큰(뒤쪽) 원소와 swap 한다. 정렬돼 있어 단조 증가가 보장되므로, 더 큰 값으로 바꿔 끼우면 그 자리의 누적 합은 x를 넘어가 회피된다.
여기서 의문 — 누적 합이 x가 되는 지점이 여러 번 생기면 어쩌나? 그럴 일이 없다. 누적 합이 x가 될 수 있는 지점은 많아야 한 번뿐이고(전체 합이 x가 아닌 한), 그 한 번만 비켜주면 끝이다.
풀이
전체 코드: thxwelchs/algorithm
#include <bits/stdc++.h>
// Phoenix And Gold
using namespace std;
void solve() {
int n, x;
vector<int> v;
cin >> n >> x;
for(int i = 0; i < n; i++) {
int a;
cin >> a;
v.push_back(a);
}
sort(v.begin(), v.end());
int sum = 0;
for(int i = 0; i < n; i++) {
sum += v[i];
}
// 어떠한 경우에도, 수열의 모든합이 x가 된다면 반드시 터질 수 밖에 없어서 NO 이다.
if(sum == x) {
cout << "NO" << '\n';
return;
}
// 위에서 정렬되었으니 수열의 단조증가성은 보장되어져있고,
// 연속된 두 수를 더했을 때 x가 된다면, 가장 마지막에 있는 수와 swap 해준다. 그러면 적어도 x보다는 무조건 크다.
// (실은 가장 마지막에 있는 수를 더할 필요 없고, 현재 위치보다 한칸 더 앞에 있는 수(i + 1)를 더해주어도 x보다는 무조건 크다는 조건이 성립한다.)
// 1. 의문? 그런데 만약 수열의 가장 마지막 수까지 더했을 때 x가 된거라면? (n - 2 + n - 1) 이 더해졌을 때의 상황이라면?
// - 실은 이미 이 상황은 이미 위 모든합이 x가 되었을 때의 조건과 같으므로 여기서는 이 상황이 나올 수가 없다.
// - 애초에 한번이라도 연속된 두수의 합이 x가 나올수 있는 부분은 단 한번 뿐이 될 것이다.
sum = 0;
int back = n - 1;
for(int i = 0; i < n; i++) {
sum += v[i];
if(sum == x) {
sum -= v[i];
int tmp = v[back];
v[back] = v[i];
v[i] = tmp;
sum += v[i];
break;
}
}
cout << "YES" << '\n';
for(int i = 0; i < n; i++) {
cout << v[i] << ' ';
}
cout << '\n';
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int t;
cin >> t;
while(t--) {
solve();
}
return 0;
}
댓글
GitHub(giscus) 댓글은 설정 완료 후 활성화됩니다.