일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- architecture
- boj
- textfield
- TEST
- MiTweet
- 코드포스
- 프로그래머스
- 암호학
- Gradle
- Hilt
- relay
- 백준
- activity
- Compose
- Coroutines
- androidStudio
- Rxjava
- android
- pandas
- livedata
- Codeforces
- ProGuard
- AWS
- Coroutine
- 쿠링
- MyVoca
- GitHub
- Python
- Kotlin
- 코루틴
- Today
- Total
이동식 저장소
327A. Flipping Game 본문
0과 1로 이루어진 길이 $N$짜리 수열이 있다. 이 수열에서 연속된 구간 $[i,~j]$를 단 한 번만 골라 구간 안에 있는 모든 0을 1로, 1을 0으로 뒤집는다. 뒤집은 후에 1은 최대 몇 개 있을 수 있을까?
이 문제는 제한이 매우 작아서 $O(N^{3})$에도 풀 수 있지만, $N$이 커지더라도 풀 수 있는 방법을 생각해 보자.
Maximum Subarray
먼저 Maximum subarray라는 개념을 알아야 한다. Maximum subaray는 배열의 끝 칸에서 끝나는 부분합 중 최댓값을 구하는 알고리즘이다. 식으로 쓰면 $ms[i]$는 $[1,~i]$ 구간에서 $i$를 포함하는 부분합 중 최댓값을 의미한다.
배열 $a$에 대해 $ms[i]=\max(ms[i-1]+a[i],~a[i])$이다.
왜요?
$ms[i-1]$까지 계산한 후에 $a[i]$를 추가할 수 있는 경우는 $ms[i-1]$ 뒤에 $a[i]$를 붙이거나 $a[i]$ 단독으로 사용하는 경우뿐이다. $ms[i-1]$ 외의 부분합에 $a[i]$를 붙였을 때 최댓값이 되는 경우는 없다. 그런 경우가 있다면 애초에 $ms[i-1]$을 잘못 계산한 것이다.
다시 문제로 돌아오자. 문제에서는 1이 최대 몇 개 존재할 수 있는지 묻고 있다. 일단 원래 배열에서 1의 개수를 센 후, 뒤집었을 때 1의 개수의 변화의 최댓값을 더하면 된다.
여기서 다시 부분합을 생각해 보자. 1이 0으로 뒤집히면 해당 구간의 부분합은 1 감소한다. 반대로 0이 1로 뒤집히면 해당 구간의 부분합은 1 증가한다. 따라서 부분합의 변화를 뜻하는 배열 $d$를 다음과 같이 선언할 수 있다.
$d[i]=\begin{cases}-1 & (a[i] = 1)\\1 & (a[i]=0)\end{cases}$
이제 $d$ 배열에서 부분합의 최댓값을 구하면 뒤집었을 때 1이 몇 개 늘어나는지(또는 줄어드는지) 알 수 있다. $d$에 대해 Maximum subarray를 계산하고, $\max_{i=1}^{n}{ms[i]}$을 구하여 더해주면 된다.
'Problem Solving > Codeforces' 카테고리의 다른 글
706C. Hard problem (0) | 2023.04.04 |
---|---|
455A. Boredom (0) | 2023.04.02 |
Codeforces Round #677 (Div. 3) 참가 후기 (0) | 2020.10.21 |
Codeforces Round #661 (Div. 3) 참가 후기 (0) | 2020.08.06 |
Codeforces Round #656 (Div. 3) 가상 참가 후기 (0) | 2020.07.31 |