스크류바가 코딩하는 블로그
카테고리아카이브태그소개
자동

© 2026 스쿠루. All rights reserved.

개인정보 처리방침RSS
2026.07.23·1 min read·PS

Replace and Keep Sorted

Codeforces Round 701 (Div. 2) B

Codeforces누적 합수학

요즘 하루에 한 문제씩 ChatGPT 예약 기능을 이용해서 문제를 추천받고 있는데요,

전형적이면서 초보자에게 추천하기 좋은 문제인 것 같아서 포스팅을 작성해 봅니다.


B - Replace and Keep Sorted

  • 난이도: 1200

네번째 조건에 따르면 각 원소 중 정확히 하나만 달라야 하므로 lil_ili​번째가 다른 경우, li+1l_i + 1li​+1번째가 다른 경우, …\dots…, ri−1r_i - 1ri​−1번째가 다른 경우, rir_iri​번째가 다른 경우를 모두 합하면 됩니다.

문제의 조건에 맞는 kkk-similar 배열을 a′a'a′라 합시다.

lil_ili​번째가 다른 경우 1≤ali′<ali+11 \leq a'_{l_i} < a_{l_i + 1}1≤ali​′​<ali​+1​이고 ali′≠alia'_{l_i} \neq a_{l_i}ali​′​=ali​​여야 하므로 ali+1−2a_{l_i + 1} - 2ali​+1​−2가지의 경우가 있습니다.

rir_iri​번째가 다른 경우 ari−1<ari′≤ka_{r_i - 1} < a'_{r_i} \leq kari​−1​<ari​′​≤k이고 ari′≠aria'_{r_i} \neq a_{r_i}ari​′​=ari​​여야 하므로 k−ari−1−1k - a_{r_i - 1} - 1k−ari​−1​−1가지의 경우가 있습니다.

그 사이의 jjj번째가 다른 경우 aj−1<aj′<aj+1a_{j - 1} < a'_j < a_{j + 1}aj−1​<aj′​<aj+1​이고 aj′≠aja'_j \neq a_jaj′​=aj​여야 하므로 aj+1−aj−1−2a_{j + 1} - a_{j - 1} - 2aj+1​−aj−1​−2개의 경우가 있습니다.

이 값들을 모두 합하면 쿼리의 답을 구할 수 있습니다.

그러나 시간 복잡도가 O(nq)O(nq)O(nq)이므로 시간 초과를 받습니다.

이때 lil_ili​번째와 rir_iri​번째를 제외하고는 lil_ili​와 rir_iri​의 값에 관계없이 경우의 수가 항상 aj+1−aj−1−2a_{j + 1} - a_{j - 1} - 2aj+1​−aj−1​−2로 일정한 것을 알 수 있습니다.

따라서 쿼리가 들어오기 전 미리 전처리하는 방식으로 해결할 수 있습니다.

Si=Si−1+aj+1−aj−1−2S_i = S_{i - 1} + a_{j + 1} - a_{j - 1} - 2Si​=Si−1​+aj+1​−aj−1​−2인 배열 SiS_iSi​를 미리 O(n)O(n)O(n)에 만들어둡니다.

그러면 쿼리의 답을 (ali+1−2)+(k−ari−1−1)+Sri−Sli−1(a_{l_i + 1} - 2) + (k - a_{r_i - 1} - 1) + S_{r_i} - S_{l_i - 1}(ali​+1​−2)+(k−ari​−1​−1)+Sri​​−Sli​−1​로 나타낼 수 있고, 이는 쿼리마다 O(1)O(1)O(1)에 처리할 수 있습니다.

따라서 시간 복잡도 O(n+q)O(n + q)O(n+q)에 문제를 해결할 수 있습니다.

코드

li=ril_i = r_ili​=ri​인 경우는 예외처리해 줘야 합니다.

#include <bits/stdc++.h>
using namespace std;
 
using ll = long long;
 
int a[101010], cnt[101010];
 
int rangeSum(int l, int r) {
    if (l > r) return 0;
    return cnt[r] - cnt[l - 1];
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int n, q, k;
    cin >> n >> q >> k;
 
    for (int i = 1; i <= n; i++) cin >> a[i];
    a[n + 1] = k + 1;
 
    for (int i = 1; i <= n; i++) {
        cnt[i] = a[i + 1] - a[i - 1] - 2;
        cnt[i] += cnt[i - 1];
    }
 
    while (q--) {
        int l, r;
        cin >> l >> r;
 
        if (l == r) cout << k - 1 << '\n';
        else
            cout << (a[l + 1] - 2) + (k - a[r - 1] - 1) + rangeSum(l + 1, r - 1)
                 << '\n';
    }
 
    return 0;
}

목차

  • B - Replace and Keep Sorted
  • 코드

댓글

이름과 이메일을 입력해 댓글을 남겨주세요.