문제
제한/스펙
1 ≤ N ≤ 250,0000 ≤ L_i ≤ 1e15, 1 ≤ D_i ≤ 1e9- 시간 제한 1초, 메모리 1GB → 
O(N log N) 풀이 필요, 누적합은 64비트 정수 사용 
입출력 형식/예제
예제 입력 1
예제 출력 1
예제 입력 2
1
2
3
4
5
  | 4
0 1
0 2
0 3
0 4
  | 
예제 출력 2
접근 개요(아이디어 스케치)
- 관찰: 어떤 시점의 고도 
h는 지금까지 사용한 풍선들의 D 합이다. 풍선 i를 사용할 수 있는 필요충분조건은 사용 직전 h ≤ L_i. - 핵심 트릭: 각 풍선에 대해 
E_i = L_i + D_i 를 정의하고 E 오름차순으로 본다. 이 순서의 접두집합에서 선택한 풍선들의 D 누적합이 항상 현재 E를 넘지 않게 유지하면, 선택 집합을 어떤 순서로든 실제로 수행할 수 있다. - 그리디: 
E 오름차순으로 순회하며 D를 최대 힙에 넣고 누적합 S를 더한다. S > E가 되면 가장 큰 D 하나를 제거하여 S를 줄인다. 이렇게 하면 같은 접두집합에서 가능한 한 많은 개수를 유지한다. - 정당성(교환 논법 요지): 현재 접두집합에서 누적합이 
E를 넘을 때 제거할 항목으로 가장 큰 D를 빼면, 이후 어떤 E에 대해서도 제약을 더 느슨하게 만들어(또는 같게 유지하여) 향후 선택 가능성을 최대화한다. 따라서 선택 개수를 최대로 하는 전략이다. 
graph TD
  A[입력 N, (L_i, D_i)] --> B[E_i = L_i + D_i 계산]
  B --> C[E 오름차순 정렬]
  C --> D{다음 풍선}
  D -->|push D_i, S+=D_i| E[최대 힙 유지]
  E --> F{S > E_i?}
  F -->|Yes| G[힙에서 가장 큰 D 제거, S-=max]
  F -->|No| H[유지]
  G --> D
  H --> D
알고리즘 설계
- 상태: 누적 상승량 
S, 최대 힙 PQ(선택한 풍선들의 D 저장) - 절차:
- 모든 풍선에 대해 
E=L+D를 계산하고 E 오름차순으로 정렬 - 각 원소를 순회하며 
D를 PQ에 넣고 S += D S > E이면 PQ에서 가장 큰 D를 꺼내 S에서 빼기- 순회 종료 시 
PQ 크기가 사용할 수 있는 최대 개수 
 - 올바름 근거: 접두집합에서 
S ≤ 현재 E 불변식을 유지. 위반 시 가장 큰 D 제거가 이후 모든 E에 가장 유리. 선택 집합에 대해 실제 수행 순서는 “사용 직전 고도 ≤ L”을 만족하도록 구성 가능. 
복잡도
- 시간: 정렬 
O(N log N) + 힙 연산 O(N log N) → 전체 O(N log N) - 공간: 힙 
O(N) 
구현 (C++)
 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
  | // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N; if(!(cin >> N)) return 0;
    vector<pair<long long,long long>> a; a.reserve(N);
    for(int i=0;i<N;++i){
        long long L,D; cin >> L >> D;
        a.emplace_back(L + D, D); // (E, D)
    }
    sort(a.begin(), a.end()); // by E asc
    priority_queue<long long> pq; // store D (max-heap)
    long long sumD = 0;
    for(const auto &p : a){
        long long E = p.first, D = p.second;
        pq.push(D);
        sumD += D;
        if(sumD > E){
            sumD -= pq.top();
            pq.pop();
        }
    }
    cout << (int)pq.size() << '\n';
    return 0;
}
  | 
구현 (Python)
 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
  | # 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
import sys
import heapq
def solve() -> None:
    data = sys.stdin.read().strip().split()
    it = iter(data)
    try:
        n = int(next(it))
    except StopIteration:
        return
    balloons = []  # (E, D)
    for _ in range(n):
        L = int(next(it)); D = int(next(it))
        balloons.append((L + D, D))
    balloons.sort()  # by E asc
    max_heap = []  # store -D to simulate max-heap
    sum_d = 0
    for E, D in balloons:
        heapq.heappush(max_heap, -D)
        sum_d += D
        if sum_d > E:
            largest = -heapq.heappop(max_heap)
            sum_d -= largest
    print(len(max_heap))
if __name__ == "__main__":
    solve()
  | 
코너 케이스 체크리스트
L_i = 0만 있는 경우: 첫 풍선만 가능 → 최대 1- 매우 큰 
L_i(최대 1e15)와 큰 D_i(최대 1e9) 혼재: sumD는 64비트(long long) 필요 - 같은 
E가 다수: 정렬 안정성에 영향 없음(임의 순서 가능) N이 큰 케이스(25만): 입출력 가속(빠른 IO), O(N log N) 구현 필수- 모든 풍선을 선택 가능한 경우: 힙 크기 
N - 한 개도 선택 불가한 구성: 답 
0 
제출 전 점검
- 64비트 정수 사용 여부(
long long) - 힙에서 제거 시 누적합 업데이트 정확성
 - 입력 파싱/개행 처리, 빠른 입출력 설정
 - 정렬 키가 
E=L+D가 맞는지 재확인 
참고자료/유사문제
- 데드라인 기반 작업 최대 개수 그리디(접두집합 누적시간 ≤ 데드라인, 위반 시 가장 긴 작업 제거)와 동일한 증명 틀을 사용. 여기서는 시작 제약을 
E=L+D로 치환하여 적용.