2020. 10. 13. 21:20ㆍProblem Solving/백준
문제
풀이
문제를 관찰하면, 수열 $ X $의 원소 $ X_{i} $에 곱해지는 수열 $ Y $의 원소들이 연속됨을 알 수 있습니다.
$ X_{i} $에 곱해지는 수의 합은 누적합을 사용하여 전처리해두면 빠르게 구할 수 있습니다.
문제는 누적합을 구현할 때 일반적으로 $ sum[i] = i $번째까지 더한 누적합이라고 정의하고 풀게되는데, 이렇게 구현하면 메모리 초과가 발생합니다.
누적합 배열을 $ sum[i] = \{j, value\} $와 같이 두고, 수열 $ Y_{j} $번째 까지 더했을 때 더한 값을 $ value $로 둡시다.
문제에서 인덱스 값의 입력이 오름차순으로 주어진다고 하였으니, 입력 순서대로 $ sum $ 배열을 만드는데, $ O(N) $만 필요합니다. (입력과 함께 처리하면 됩니다.)
그리고, 문제에서 구해야하는 $ S(a, b) $에서 수열 $ X_{i} $에 대해 더해지는 수열 $ Y $의 구간은 $ i + a $부터 $ i + b $입니다. (단, $ a <= b $)
또한, 누적합 배열 $ sum $에서 필요한 구간의 합을 구하려면 구간 $ i + a $와 $ i + b $를 배열 $ sum $에 대해서 이분 탐색을 사용하여 빠르게 처리할 수 있습니다. 이분 탐색을 사용하면 각 $ X_{i} $에 대해 $ O(logM) $의 시간 복잡도를 가집니다.
한편, 수열 $ X $의 길이는 $ N $이므로 전체 시간 복잡도는 $ O(NlogM) $이 됩니다.
소스코드
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
vector<pii> x, y_sum;
int main() {
cin.tie(0)->sync_with_stdio(0);
int n;
cin >> n;
for (int i = 0; i < n; i++) {
ll a, b;
cin >> a >> b;
x.emplace_back(a, b);
}
int m;
cin >> m;
y_sum.resize(m + 1);
y_sum[0] = {-1, 0};
for (int i = 1; i <= m; i++) {
cin >> y_sum[i].first >> y_sum[i].second;
y_sum[i].second += y_sum[i - 1].second;
}
ll a, b, ans = 0;
cin >> a >> b;
--a;
for (const auto &p : x) {
ans += p.second * (
min(y_sum.begin() + m, max(y_sum.begin(), lower_bound(y_sum.begin(), y_sum.end(), pii{p.first + b, 1e9}) - 1))->second
- max(y_sum.begin(), lower_bound(y_sum.begin(), y_sum.end(), pii{p.first + a, 1e9}) - 1)->second
);
}
cout << ans;
}
'Problem Solving > 백준' 카테고리의 다른 글
백준 17612번, 한국정보올림피아드 KOI 2019년 1차 대회 고등부 1번, 쇼핑몰 풀이 (0) | 2020.10.15 |
---|---|
백준 4195번, 친구 네트워크 풀이 (0) | 2020.10.14 |
백준 1226번, BOI 2008 4번, 국회 풀이 (0) | 2020.10.12 |
백준 14867번, 한국정보올림피아드 2017년 고등부 1번, 물통 풀이 (0) | 2020.10.11 |
백준 2473번, 한국정보올림피아드 2010년 고등부 1번, 세 용액 풀이 (0) | 2020.10.10 |