레야몬
[C++] 3015번 오아시스 재결합 - 자료 구조, 스택 본문
1. 문제
- 두 사람 A, B가 서로 볼 수 있으려면, 두 사람 사이에 A 또는 B보다 키가 큰 사람이 없어야 한다. 줄에 서 있는 사람의 키가 주어질 때, 서로 볼 수 있는 쌍의 수를 구하는 프로그램을 작성하시오
<입력>
- - 1 - 기다리는 사람의 수 \(N(1 \leq N \leq 500,000)\)
- - N개의 줄 - 키 \(height(1 \leq height \leq 2^{31})\)
<출력>
- 서로 볼 수 있는 사람의 수
2. 재정의
- 수열이 주어질 때 두 수 사이에 있는 값이 더 작거나 같은 두 수의 순서쌍의 개수를 구하라
3. 해결 방법
- 순차적으로 같거나 내려갈 경우 스택에 추가
- 올라갈 경우 스택에 있는 키를 꺼내는데 같은 키의 개수를 구하자
- 같은 키의 개수를 더하고 스택에 더 있으면 한 번 더 더하자.
- 같은 키C2만 큼 ㄱㄴ하므로 이것도 더하자
- 다 하고 나서 위에서 한 번 더!
4. 실수한 점, 개선할 점
- NC2를 계산할 때 int범위를 넘어갈 수 있다.
<코드>
#include <iostream>
#include <stack>
#define fastio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 500001;
// <문제>
// 기다리고 있는 사람의 수 N
int N;
// 사람들의 키 height
int height[MAX_N];
// 사람 번호를 넣는 스택
stack<int> s;
// 서로 볼 수 있는 쌍의 수
ll cnt;
void input() {
fastio;
cin >> N;
for(int i=0; i<N; i++)
cin >> height[i];
}
void solve() {
int sameCnt, before;
for(int i=0; i<N; i++) {
if(s.empty())
s.push(i);
else {
// 전 사람의 키
before = height[s.top()];
// 전 사람의 키보다 작거나 같으면 스택에 추가
if(before >= height[i])
s.push(i);
// 전 사람의 키보다 크면 쌍의 수 계산
else {
// 스택이 비거나 더 큰 키가 나올 때까지 스택에서 제거하면서 쌍의 수 추가
sameCnt;
while(!s.empty()) {
sameCnt = 1;
before = height[s.top()];
if(before >= height[i])
break;
s.pop();
// 같은 키의 수 세기
while(!s.empty() && before == height[s.top()]) {
s.pop();
sameCnt++;
}
cnt += sameCnt + 1ll * sameCnt * (sameCnt - 1) / 2;
if(!s.empty())
cnt += sameCnt;
}
s.push(i);
}
}
}
// 스택이 비거나 더 큰 키가 나올 때까지 스택에서 제거하면서 쌍의 수 추가
while(!s.empty()) {
before = height[s.top()];
s.pop();
sameCnt = 1;
// 같은 키의 수 세기
while(!s.empty() && before == height[s.top()]) {
s.pop();
sameCnt++;
}
cnt += 1ll * sameCnt * (sameCnt - 1) / 2;
if(!s.empty())
cnt += sameCnt;
}
}
int main() {
input();
solve();
cout << cnt;
return 0;
}
※현재 고등학교 등교 중인 학생입니다. 이제 알고리즘을 본격적으로 공부하기 시작해서 아직 초보입니다. 혹시 제가 잘못 알고 있는 점이나 더 좋은 풀이 방법이 있어 댓글에 남겨주시면 감사히 하나하나 열심히 읽어보겠습니다. 좋아요, 단순한 댓글 한마디라도 저에겐 큰 힘이 됩니다! 감사합니다.
'알고리즘 > 백준' 카테고리의 다른 글
[C++] 1450번 냅색문제 - 이분 탐색, 중간에서 만나기 (0) | 2022.12.08 |
---|---|
[C++] 9370번 미확인 도착지 - 그래프 이론, 데이크스트라 (0) | 2022.12.08 |
[C++] 1655번 가운데를 말해요 - 자료 구조, 우선순위 큐 (0) | 2022.12.06 |
[C++] 10830번 행렬 제곱 - 수학, 분할 정복, 분할 정복을 이용한 거듭제곱, 선형대수학 (0) | 2022.12.06 |
[C++] 13977번 이항 계수와 쿼리 - 수학, 정수론, 조합론, 분할 정복을 이용한 거듭제곱, 모듈로 곱셈 역원, 페르마의 소정리 (0) | 2022.12.03 |
Comments