티스토리 뷰

알고리즘/백준

백준 / 1637 날카로운 눈

4567은 소수 2021. 3. 26. 20:12

www.acmicpc.net/problem/1637

 

1637번: 날카로운 눈

첫째 줄에 입력의 개수 N이 주어진다. N은 1이상 20,000이하인 수이다. 그 다음 줄부터 N줄에 걸쳐 세 개의 정수 A, C, B가 주어지는데, 이것은 A, A+B, A+2B, ..., A+kB (단, A+kB ≦ C) 의 정수들이 정수더미

www.acmicpc.net

가능한 입력이 MAX_INT 까지이므로 하나하나 개수를 세면 시간을 초과합니다. 

log n으로 찾을만한 이분 탐색을 사용하려 했지만 아이디어가 떠오르지 않아 www.acmicpc.net/board/view/18341 글을 참고했습니다.

 

f(x) 를 입력에 대해 x 이하의 수의 개수라고 합니다.

x 이하의 수의 개수는 i번째 입력에 대해 

a>x 일 때 0개,

아닐 때 (min(x , c) - a) / b + 1 개임을 구할 수 있습니다.

 

홀수인 수는 하나 또는 0개 뿐이므로 f(x)가 홀수이면 x 이하의 수 중 정답이 존재하고, 아니면 x보다 큰 값 중 정답이 있을 수도 있습니다. (f(x)가 홀수인 것이 없는 경우 존재)

 

그러므로 이분 탐색을 통해 주어진 범위 내에서 하나로 좁혀진 x를 구한 뒤, f(x) - f(x-1) 을 구해주면 됩니다.

left 값이 inf (범위 밖) 을 넘어간다면, f(x)가 홀수인 것이 존재하지 않는 경우입니다.

 

코드는 다음과 같습니다.

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

typedef long long ll;

int n;
// n개 입력에 대해 a,c,b 값 저장
ll a[20001];
ll b[20001];
ll c[20001];

void init()
{
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i] >> c[i] >> b[i];
	}
}

// f(x) : n개 입력에 대해 x 이하의 수의 개수
// n개 입력에 대해 돌면서
// a[i]가 시작점, c[i]가 최댓값, b[i]가 간격이므로
// i번째 입력에서의 x 이하의 수의 개수 = max(0, (min(x,c[i])-a[i])/b[i] + 1)
// ex) i번째 입력 a=2 c=300 b=3, x=120
// 2, 5, 8, ....., 299
// 위 수열에서 120 이하인 수의 개수 : 40개 (2, 5, ..., 119)
// min(120,300) = 120, 120-2=118, 118/3=39, 39+1=40
// 이렇게 n개 입력에 대해 다 더한 값 f(x)가 홀수면 x이하에 답 존재
// 짝수면 아직 안 나옴 => x 이후에 답 존재 
// 이분 탐색으로 가능한 x 범위 좁혀나가기
// x가 범위 내이면 x가 정답, 개수는 f(x)-f(x-1)
// 아니면 홀수개인 것은 없음
ll func(ll x)
{
	ll sum = 0;
	for (int i = 0; i < n; i++) {
		if (a[i] > x)
			continue;
		sum += ((min(x, c[i]) - a[i]) / b[i] + 1ll);
	}
	return sum;
}

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

	init();

	ll inf = 1ll << 32;
	ll left, right, mid;
	left = 0;
	right = inf;
	mid = (left + right) >> 1;

	// 이분 탐색
	while (1)
	{
		if (left >= right)
			break;

		ll sum = func(mid);
		if (sum & 1) {
			right = mid;
			mid = (left + right) >> 1;
		}
		else {
			left = mid + 1;
			mid = (left + right) >> 1;
		}
	}

	// x 위치 정해짐
	ll answer = func(left) - func(left - 1);
	if (left==inf) {
		cout << "NOTHING";
	}
	else {
		cout << left << ' ' << answer;
	}
}

 

'알고리즘 > 백준' 카테고리의 다른 글

백준 / 1019 책 페이지 C++  (0) 2021.03.29
백준 / 14725 개미굴  (0) 2021.03.28
백준 / 9376 탈옥 C++  (0) 2021.03.25
백준 / 13549 숨바꼭질 3 C++  (0) 2021.03.23
백준 / 3584 가장 가까운 공통 조상  (0) 2021.03.22
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2024/12   »
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
글 보관함