※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 24838번 문제인 배열 구간합 놀이이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/24838
24838번: 배열 구간합 놀이
각 테스트 케이스의 정답인 Alice가 달성할 수 있는 $S(A, x, y)$의 최댓값, 그리고 이를 달성할 수 있는 방법의 수를 공백으로 구분하여 출력한다. 단, 방법의 수가 매우 커질 수 있으므로 $10^9+7$로
www.acmicpc.net
크기 배열의 각 칸 x에 대하여 cnt[x]를 M개의 구간 중 몇 개의 구간이 x를 포함하는지를 나타내는 배열이라 하자. 모든 x에 대한 cnt[x]를 알 수 있다면 cnt[x]와 A의 각 원소들을 크기순으로 짝을 맞춰 곱해 더하는 greedy 전략으로 문제를 해결할 수 있음을 관찰할 수 있다.
cnt[x]의 경우 1차원에서의 imos법을 이용해 O(N + M)의 시간복잡도로 구할 수 있다. 구체적으로, 먼저 각 구간 [L,R]에 대하여 cnt[L]에 1을 더하고 cnt[R+1]에 -1을 더하는 것을 반복하자. 이러한 작업뒤에 현 cnt배열을 cnt배열의 구간합 배열로 바꾸면 구하려는 cnt배열을 얻을 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
int T;
int N, M;
int arr[50001];
int cnt[50001];
ll fact[50001];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
fact[0] = fact[1] = 1;
for (ll i = 2; i < 50001; i++) fact[i] = (fact[i - 1] * i) % 1000000007;
cin >> T;
while (T--) {
memset(arr, 0, sizeof(arr));
memset(cnt, 0, sizeof(cnt));
cin >> N >> M;
for (int n = 0; n < N; n++) cin >> arr[n];
while (M--) {
int L, R; cin >> L >> R;
cnt[L - 1]++, cnt[R]--;
}
for (int n = 1; n < N; n++) cnt[n] += cnt[n - 1];
sort(arr, arr + N);
sort(cnt, cnt + N);
ll ans = 0;
for (int i = 0; i < N; i++) {
ans += (ll)arr[i] * (ll)cnt[i];
}
ll ans2 = 1;
int old = cnt[0]; ll combo = 1;
for (int i = 1; i < N; i++) {
if (cnt[i] == old) combo++;
else {
ans2 = (ans2 * fact[combo]) % 1000000007;
old = cnt[i], combo = 1;
}
}
ans2 = (ans2 * fact[combo]) % 1000000007;
cout << ans << ' ' << ans2 << '\n';
}
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 27210 // C++] 신을 모시는 사당 (0) | 2023.01.20 |
---|---|
[BOJ 27214 // C++] Сетка (0) | 2023.01.20 |
[BOJ 23324 // C++] 어려운 모든 정점 쌍 최단 거리 (0) | 2023.01.19 |
[BOJ 27220 // C++] Ромб (0) | 2023.01.18 |
[BOJ 23323 // C++] 황소 다마고치 (0) | 2023.01.18 |