Algorithm/BOJ
[백준 13144] List of Unique Numbers cpp
connieya
2022. 3. 1. 16:23
https://www.acmicpc.net/problem/13144
13144번: List of Unique Numbers
길이가 N인 수열이 주어질 때, 수열에서 연속한 1개 이상의 수를 뽑았을 때 같은 수가 여러 번 등장하지 않는 경우의 수를 구하는 프로그램을 작성하여라.
www.acmicpc.net
문제
길이가 N인 수열이 주어질 때, 수열에서 연속한 1개 이상의 수를 뽑았을 때 같은 수가 여러 번 등장하지 않는 경우의 수를 구하는 프로그램을 작성하여라.
입력
첫 번째 줄에는 수열의 길이 N이 주어진다. (1 ≤ N ≤ 100,000)
두 번째 줄에는 수열을 나타내는 N개의 정수가 주어진다. 수열에 나타나는 수는 모두 1 이상 100,000 이하이다.
출력
조건을 만족하는 경우의 수를 출력한다.
풀이
전형적인 투 포인터 알고리즘 문제이다.
n개의 수열이 담긴 배열을 투 포인터로 탐색 한다.
같은 수가 여러 번 들어 있는지 확인 하는 check 배열을 통해
여러 번 들어있지 않으면 오른쪽 (rt) 포인터를 이동시킨다.
만약 같은 수가 여러번 등장할 경우
전체 경우의 수에서 해당 범위 (n-rt) 를 빼준뒤
lt (왼쪽 포인터)을 이동한다.
왼쪽 포인터를 이동하면서 check 배열을 초기화 시켜줘야 한다.
이런식으로 rt가 배열 끝에 도달할 때 까지 탐색을 하면
O(n) 의 시간 복잡도로 문제를 해결 할 수 있다.
※ 연속한 n개 이상의 수를 뽑는 경우의 수 => n(n+1) / 2
코드는 다음과 같다.
#include "bits/stdc++.h"
using namespace std;
int arr[100001];
bool checked[100001];
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
long long n, ans;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> arr[i];
}
ans = n * (n + 1) / 2;
int lt = 0;
int rt = 1;
checked[arr[lt]] = true;
while (rt < n) {
if (checked[arr[rt]]){
checked[arr[lt]] = false;
lt++;
ans -= n-rt;
}else {
checked[arr[rt]] = true;
rt++;
}
}
cout << ans;
}