※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 3007번 문제인 숫자 원이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/3007
3007번: 숫자 원
첫째 줄에 두 번째 숫자 원에 쓰여 있는 수의 개수 N이 주어진다. (3 ≤ N ≤ 10,000) 다음 N개 줄에는 원에 쓰여 있는 수가 원을 이루는 순서대로 주어진다. 숫자는 109보다 작은 자연수이다. 입력으
www.acmicpc.net
N=3인 경우는 문제를 간단히 해결할 수 있으므로 N이 3보다 큰 경우에 대해 생각해보자.
주어진 원의 i번째 수와 i+1번째 수를 각각 \(b_{i}\)와 \(b_{i+1}\)이라 하자. 이 때, \(b_{i} = a_{i-1} + a_{i} + a_{i+1}\)이고 \(b_{i+1} = a_{i} + a_{i+1} + a_{i+2}\)이므로 \(b_{i+1}-b_{i}=a_{i+2}-a_{i-1}\)가 성립한다.
위의 관찰을 이용하면 모든 i에 대하여 \(a_{i}\)와 \(a_{i+3}\)의 차들을 각각 구할 수 있다.
N이 3의 배수가 아닌 경우를 생각해보자. 이 경우, 모든 \(a_{i}\)를 \(a_{0} = x\)를 기준으로 \(x+k_{i}\)의 형태로 표현할 수 있다. \(b_{i}\)의 총합을 3으로 나눈 값이 \(a_{i}\)의 총합과 같다는 점을 이용하면, 식을 세워 \(x\)의 값을 구해내 문제를 해결할 수 있다.
N이 3의 배수인 경우를 생각해보자. 이 경우, 모든 \(a_{i}\)를 \(a_{0} = x, a_{1} = y, a_{2} = z\)를 기준으로 \(x+k_{i}\) 또는 \(y+k_{i}\) 또는 \(z+k_{i}\)의 형태로 표현할 수 있다. \(b_{i}\)의 총합을 3으로 나눈 값이 \(a_{i}\)의 총합과 같다는 점을 이용하면, 식을 세워 \(x+y+z\)의 값을 구해내 \(x, y, z\)의 값을 적절히 정하여 문제를 해결할 수 있다. \(x, y, z\)의 값을 결정할 때 모든 \(a_{i}\)의 값이 1 이상 1000000000 미만이어야 한다는 조건을 만족시켜야 함에 유의하자.
아래는 제출한 소스코드이다.
#include <iostream>
using namespace std;
typedef long long ll;
int N;
ll S[10000];
ll ans[10000];
ll fcnt = 0, total = 0, difftotal = 0, val;
void func1(int cur, ll diff) {
difftotal += diff;
int nxt = cur + 1;
if (nxt == N) nxt = 0;
ll nxtdiff = diff + S[nxt] - S[cur];
nxt += 2;
if (nxt >= N) nxt -= N;
if (nxt) func1(nxt, nxtdiff);
else val = (total - difftotal) / fcnt;
ans[cur] = val + diff;
}
ll diffs[10000];
void func2(int cur, int s0, ll diff) {
diffs[cur] = diff;
difftotal += diff;
int nxt = cur + 1;
if (nxt == N) nxt = 0;
ll nxtdiff = diff + S[nxt] - S[cur];
nxt += 2;
if (nxt >= N) nxt -= N;
if (nxt != s0) func2(nxt, s0, nxtdiff);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for (int i = 0; i < N; i++) {
cin >> S[i];
total += S[i];
}
total /= 3;
if (N == 3) {
cout << 1 << '\n' << 1 << '\n' << S[0] - 2;
}
else {
if (N % 3) {
fcnt = N;
func1(0, 0);
}
else {
fcnt = N / 3;
func2(0, 0, 0);
func2(1, 1, 0);
func2(2, 2, 0);
val = (total - difftotal) / fcnt;
ll mnx = 0, mxx = 0, mny = 0, mxy = 0, mnz = 0;
for (int i = 0; i < N; i += 3) mnx = min(mnx, diffs[i]), mxx = max(mxx, diffs[i]);
for (int i = 1; i < N; i += 3) mny = min(mny, diffs[i]), mxy = max(mxy, diffs[i]);
for (int i = 2; i < N; i += 3) mnz = min(mnz, diffs[i]);
ll x = -mnx + 1, xR = 999999999LL - mxx;
ll y = -mny + 1, yR = 999999999LL - mxy;
ll z = -mnz + 1;
val -= x + y + z;
ll tmp = min(xR - x, val);
x += tmp, val -= tmp;
tmp = min(yR - y, val);
y += tmp, val -= tmp;
z += val;
for (int i = 0; i < N; i += 3) ans[i] = x + diffs[i];
for (int i = 1; i < N; i += 3) ans[i] = y + diffs[i];
for (int i = 2; i < N; i += 3) ans[i] = z + diffs[i];
}
for (int i = 1; i < N; i++) cout << ans[i] << '\n';
cout << ans[0];
}
}
'BOJ' 카테고리의 다른 글
[BOJ 14369 // C++] 전화번호 수수께끼 (Small) (1) | 2023.04.30 |
---|---|
[BOJ 14370 // C++] 전화번호 수수께끼 (Large) (0) | 2023.04.29 |
[BOJ 7868 // C++] 해밍 수열 (0) | 2023.04.27 |
[BOJ 7869 // C++] 두 원 (0) | 2023.04.26 |
[BOJ 2693 // C++] N번째 큰 수 (0) | 2023.04.25 |