DY N DY
koitp 세금(TAX)(C++) 본문
시간 제한 | 메모리 제한 | 제출 횟수 | 정답 횟수 (비율) | 정답자 수 |
---|---|---|---|---|
1.5 초 | 512 MB | 1073 | 64 (6%) | 38 |
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #include <cstdio> #include <algorithm> #include <queue> #include <functional> #include <vector> #pragma warning(disable:4996) long long int D[1111111][55]; long long int n[1111111]; std::priority_queue<long long int, std::vector<long long int>, std::greater<long long int>> res; bool comp(long long int a, long long int b){ return a > b; } int main(void){ int N, K; scanf("%d%d", &N, &K); for (int i = 1; i <= N; ++i) scanf("%lld", &n[i]); D[1][1] = n[1]; res.push(D[1][1]); K++; for (int i = 2; i <= N; ++i) { D[i][1] = std::max(D[i - 1][1], (long long int)0) + n[i]; D[i][2] = std::min(D[i - 1][1], (long long int)0) + n[i]; for (int j = 3; j <= (i / K > 0 ? K : i%K); ++j) { D[i][j] = D[i - 1][j - 1] + n[i]; } for (int j = 2; j < (i / K > 0 ? K : i%K); ++j) { if (D[i][j] < D[i][j + 1]) std::swap(D[i][j], D[i][j + 1]); } } K--; for (int i = 1; i <= N; ++i) { if (res.size() == K && D[i][1] < res.top()) continue; for (int z = 1; z <= (i / K > 0 ? K : i%K); ++z) { if (res.size() < K) res.push(D[i][z]); else if (res.top() < D[i][z]) { res.pop(); res.push(D[i][z]); } } } printf("%lld\n", res.top()); } | cs |
dynamic programing
연속된 수에서 k번째 가장 큰 수를 찾는 문제이다.
priority queue(heap)을 이용하여 풀었다.
사실 이게 맞는 답인지는 모르겠지만 우선은 해당 사이트에서는 100점으로 통과를 했다..
(1.5초 제한에 가장 길게 나온게 1.2초나 되서 최적화를 더 할 수 있을 것 같기는 하다.)
k번째 최단경로를 푼 후부터 k번째 큰/ k번째 작은 같은 문제가 나오면 뭔가 힙을 이용해야 할 것 같은 느낌이 들기 시작했다...
이 문제는 두 가지를 생각하면 풀린다.
1. i번째까지, i를 포함하는 가장 큰 부분합은 D[i][1]이라고 하였다.
이때, D[i][1] = max(D[i-1][1], 0) + n[i]이다. 사실 이 공식은 약간 유명?까진 아니어도 가장 큰 부분합을 구하는 공식으로 사용된다.
(사실 이렇게 구한 D[i][1]들 중에 가장 큰 D[x][1]이 전체 수열의 가장 큰 부분합이 된다. - D[i][1]은 i를 꼭 포함하는 가장 큰 부분합일 뿐.)
2. k번째 큰 부분합은 각 i번째를 포함한 k번째 큰 부분합들 중에 있다.
i길이까지, i를 포함하는 k번째 큰 부분합은 D[i][k]라고 할 때 이는 max(D[i-1][k],0) + n[i]이 된다.
이렇게 된다면 결국
연산해야 할 것은 n개 날짜 중 k번째를 구하기 위해 n*k연산을 하면 된다.
이후 모든 수를 min-heap에 넣어주어 top을 출력하였다.
heap은 k개 이상 들어가지 않게 하였기 때문에 root가 결국 k번째로 큰 부분합이라고 할 수 있다.
'PARK > ALGORITHM' 카테고리의 다른 글
실력키우기 색종이(고)(C++) (1) | 2016.09.29 |
---|---|
실력키우기 연속부분최대곱(C++) (1) | 2016.09.28 |
실력키우기 하노이의 탑(C++) (0) | 2016.09.27 |
BOJ 1854 K번째 최단경로 찾기(C++) (0) | 2016.09.22 |
koitp 48560 K번째 최단 경로(KTHSHORTEST)(C++) (0) | 2016.09.22 |