포스트

BOJ 1994 등차수열

sorohue가 PS하는 블로그

BOJ 1994 등차수열

문제 링크입니다.

문제 요약

주어진 $N$개의 수로 최대한 긴 등차수열을 만드세요.

풀이

주어진 수들을 오름차순 정렬합니다. 원하는 값을 ${\cal O}(\lg N)$에 찾을 수 있게 하기 위함입니다. 공차는 음이 아닌 정수로 제한하겠습니다. 공차가 음수인 경우는 탐색 방향만 다른 거라 굳이 해 볼 필요 없습니다.

등차수열 상 연속한 두 수의 쌍으로 가능한 것은 ${\cal O}(N^2)$가지입니다. 두 값을 각각 $a \le b$라고 하면, 등차수열 상 다음에 올 수 있는 값은 $2b-a$로 고정됩니다. 해당 값이 존재하는 지를 이분 탐색으로 찾으면 ${\cal O}(N^2 \lg N)$에 모든 쌍에 대한 다음 수의 위치를 찾아낼 수 있습니다.

이를 이용해 $d[i][j]$를 첫 두 수가 $A_i, A_j$인 등차수열의 최대 길이로 정의하고 DP를 수행하면 우리가 원하는 답을 얻어낼 수 있습니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
using namespace std;
map<int, int> cnt;
vector<int> v;
int d[2020][2020];

int dp(int i, int j){
	int& ret = d[i][j];
	if(ret) return ret;
	ret = 2;
	int nxt = lower_bound(v.begin()+j, v.end(), 2*v[j]-v[i]) - v.begin();
	if(v[nxt] != 2*v[j]-v[i]) return ret;
	return ret = 1 + dp(j, nxt);
}

int main(){
	cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
	int n, ans = 2; cin >> n;
	if(n == 1) return !(cout << 1);
	for(int i = 0; i < n; i++){
		int k; cin >> k;
		if(cnt.find(k) != cnt.end()){
			cnt[k]++;
			ans = max(ans, cnt[k]);
		}
		else{
			cnt.insert({k,1});
			v.push_back(k);
		}
	}
	sort(v.begin(), v.end());
	for(int i = 0; i < v.size(); i++){
		for(int j = i+1; j < v.size(); j++){
			ans = max(ans, dp(i, j));
		}
	}
	cout << ans;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.