문제
- 문제 링크
BOJ 24505 - blobhyperthink
길이 $N$의 수열이 주어진다.
이 수열에서, 길이가 $11$인 증가수열의 개수를 $10^9+7$로 나눈 나머지를 구해보자.
TL : $2$ sec, ML : $1024$ MB
$1 ≤ N ≤ 10^5$ $1 ≤ A_i ≤ N$
알고리즘 분류
- 다이나믹 프로그래밍(dp)
- 자료 구조(data_structures)
- 세그먼트 트리(segtree)
풀이
$N$이 적당히 작았다면, 각 $i$마다 이전 수열을 순회하며 답을 계산하는 $O(N^2)$에 풀 수 있을 테지만 $N ≤ 10^5$이다.
$[A_1, A_i]$에서 길이가 $k$인 증가 수열의 개수를 구한다고 해보자.
이는 $A_1$, $A_2$, ... , $A_{i-1}$인 $A_j$에 대해, $A_i > A_j$를 만족하는 모든 $[A_1, A_j]$에서 길이가 $k - 1$인 증가 수열의 개수합과 같다.
$11$개의 합 세그먼트 트리를 두자.
각 $i$마다 $A_i$를 끝으로 하는 길이 $1, 2, ... , 11$인 증가 수열의 개수를 누적하자.
앞서 말했다시피, 길이가 $k$인 증가 수열의 개수를 계산할 땐 $k - 1$번 세그먼트 트리에 $[1, A_i-1]$만큼 합쿼리를 날리는 것과 같다.
모든 $i$에 대한 업데이트가 끝난다면, 답은 $11$번 세그먼트 트리에 $[1, 10^5]$만큼 합쿼리를 날리는 것과 같다.
시간 복잡도는 상수가 조금 붙은 $O(NlogN)$.
전체 코드
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 32 33 34 35 | #include<bits/stdc++.h> #define N 100001 using namespace std; const int mod(1e9 + 7); int seg[12][N]; void update(int u, int x, int val) { for (; x < N; x += x & -x) if (seg[u][x] += val; seg[u][x] >= mod) seg[u][x] -= mod; } int query(int u, int x, int res = 0) { for (; x; x -= x & -x) if (res += seg[u][x]; res >= mod) res -= mod; return res; } int main() { int n; cin >> n; for (int i(1); i <= n; i++) { int x; scanf("%d", &x); update(1, x, 1); for (int k(2); k < 12; k++) { int val(query(k - 1, x - 1)); update(k, x, val); } } cout << query(11, 1e5); } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Platinum)' 카테고리의 다른 글
백준 30515 - 방형구 탐색 (Hard) (C++) (1) | 2023.11.12 |
---|---|
백준 20933 - 마스크펑크 2077 (C++) (1) | 2023.11.11 |
백준 30466 - 우정은 BFS처럼, 사랑은 DFS처럼 (C++) (0) | 2023.11.06 |
백준 23314 - Minimum Spanning Cactus (C++) (1) | 2023.10.09 |
백준 21025 - Healthy Lifestyle (C++) (1) | 2023.10.04 |