본문 바로가기

PS - 알고리즘

13215 - Fish

step 1

더보기

N개의 세그먼트가 있다고 해봅시다. 저희가 이미 어떤 방법을 통해서 [1, N/2], [N/2+1, N] 영역에 대해 답을 구했다고 해봅시다. 그럼 이 두 영역에 모두 걸쳐있는 영역에 대해 답을 구하면 문제를 해결할 수 있습니다.

step 2

더보기

[1, N/2] 영역에서 오른쪽 부분합 [N/2+1, N] 영역의 왼쪽 부분합을 구합니다. 오른쪽 부분합은 영역의 오른쪽 부터 왼쪽으로 쭉 진행하면서 나온 값들을 쭉 더해온 값입니다. 왼쪽 부분합은 왼쪽부터 진행한 것입니다.

 

이 부분합들을 각각 정렬합니다. 그리고 투포인터를 이용하면 두 영역에 모두 걸쳐있는 영역의 답을 구할 수 있습니다.

분할정복으로 두 영역에 대해 답을 구하고 투포인터로 합쳐주면 됩니다.

코드

더보기
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm>
using namespace std;
long long int r[300000], l[300000],cnt=0,mm,sum[300000];
void find(long long int s, long long int e) {
	if (s == e) {
		if (r[s] >= mm) cnt++;
		return;
	}
	find(s, (s + e) / 2);
	find((s + e) / 2 + 1, e);
	long long int m = (s + e) / 2 + 1, i, tar = m;
	for (i = m;i <= e;i++) {
		while (1) {
			if (tar == s) break;
			if (l[i] + r[tar - 1] >= mm) tar--; else break;
		}
		cnt += m - tar;
	}
	for (i = m;i <= e;i++)l[i] += sum[m - 1] - sum[s - 1];
	for (i = s;i < m;i++) r[i] += sum[e] - sum[m - 1];
	sort(r + s, r + e + 1);
	sort(l + s, l + e + 1);
}
int main() {
	long long int n, i, j;
	scanf("%lld%lld", &n, &mm);
	for (i = 1;i <= n;i++) {
		long long int x;
		scanf("%lld", &x);
		l[i] = x;
		r[i] = x;
		sum[i] = sum[i - 1] + x;
	}
	find(1, n);
	printf("%lld", cnt);
	return 0;
}

'PS - 알고리즘' 카테고리의 다른 글

12877 - 먹이 사슬  (0) 2024.11.11
15005 - Collatz Conjecture  (0) 2024.11.04
11025 - 요세푸스 문제 3  (0) 2024.10.14
23755 - 카드컨트롤 (Hard)  (0) 2024.10.07
24520 - Meet In The Middle  (0) 2024.09.30