본문 바로가기

백준 문제 풀이

백준 25401번 카드 바꾸기 (C++)

728x90

https://www.acmicpc.net/problem/25401

 

25401번: 카드 바꾸기

$N$개의 카드가 놓여있다. 편의상 가장 왼쪽에 있는 카드를 $1$번 카드, 그 다음에 있는 카드를 $2$번 카드 $\dots$, 가장 오른쪽에 있는 카드가 $N$번 카드라고 하자. $N$개의 카드에는 각각 정수가 하

www.acmicpc.net

 

수학적인 테크닉이 조금 필요한 문제이다. 일정하게 증가,감소 수열을 만들어야하기 때문에 처음 떠오른 방식은 dp, 이분탐색이었다.

 

1. DP : 내가 DP를 잘 못하기도 하고 어떻게 점화식을 짜야할지 감이잡히지 않았다.

2. 이분탐색: 숫자의 범위가 -100만~ 100만이기 때문에 이분탐색을 떠올리고 가장 최적의 증가, 감소치를 찾으면 될 것이라 생각하였으나. 만약 4를 공차라고 하였을 때 결과가 10이라 한다면 이 때 이분탐색으로 upper탐색을 할 지 lowwer 탐색을 할 지 결정할 수 없다.

 

문제의 열쇄는 " 두 개의 카드를 고른 후 이 두개의 카드는 바뀌지 않는다 "를 생각해내면 문제가 풀린다. 

 

2 9 1 2 10 라 할 때 2와 10을 선택했다고 가정하자. 그렇다면 인덱스는 i = 0, j = 4라고 가정할 수 있다.

 

그리고 이 둘이 바뀌지 않을 떄. 즉 이 두 카드를 기준으로 공차를 만들었을 때 답이라고 가정하면 

 

value[i] - value[j] / i - j = -8 / -4 = 2

 

이제 i 혹은 j를 기준으로 양옆을 전부 공차가 2인 경우로 바꿔주면서 만약 원래 값과 같다면 카운팅하지 않으면 된다.

이 경우 두개를 고정하고, N번을 돌아야 하므로 총 시간 복잡도는 O(N^3)으로 문제를 해결할 수 있다.

 

#include <iostream>
#include <vector>
using namespace std;

vector<int> card;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);

	int N;
	cin >> N;
	card = vector<int>(N);
	for (int i = 0; i < N; i++) {
		cin >> card[i];
	}
	int answer = 501;

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			int cnt = 0;
			if (i == j || (card[i] - card[j]) % (i - j) == 0) {
				int gap;
				if (i == j) gap = 0;
				else gap = ((card[i] - card[j]) / (i - j));
				vector<int> tmp = card;
				for (int k = i + 1; k < N; k++) {
					int value = gap + tmp[k - 1];
					if (value != card[k]) cnt++;
					tmp[k] = value;
				}

				for (int k = i - 1; k > -1; k--) {
					int value = tmp[k + 1] - gap;
					if (value != card[k]) cnt++;
					tmp[k] = value;
				}

				answer = min(answer, cnt);
			}
		}
	}

	cout << answer << '\n';
}

 

'백준 문제 풀이' 카테고리의 다른 글

백준 1823번 수확 (C++)  (0) 2024.03.27
백준 9024번 두 수의 합(C++)  (0) 2024.03.26
백준 2758번 - 로또(C++)  (0) 2024.03.08
백준 11062번 카드 게임 C++  (0) 2024.03.07
백준 2357 최솟값과 최댓값 (c++)  (0) 2024.02.06