[APIO/CTSC2007] 데이터 백업 문제 해결
23058 단어 dp
우선 수조를 차분시키면 차분수 그룹에서 kk개의 서로 인접하지 않는 수를 찾아 그것들의 수를 최소화해야 한다.
먼저 폭력적인 DP 방법이 하나 있다. f(i, j, 0/1) f(i, j, 0/1) f(i, j, 0/1)는 앞의 i i i 개수를 표시하고 j j 개, 첫 번째 i i 개수는 선택하지 않거나 선택하지 않으며 가장 작은 것이 얼마인지를 나타낸다.f ( i , j , 0 ) = min ( f ( i − 1 , j , 0 ) , f ( i − 1 , j , 1 ) ) , f ( i , j , 1 ) = f ( i − 1 , j − 1 , 0 ) + d i f(i,j,0)=\min(f(i-1,j,0),f(i-1,j,1)),f(i,j,1)=f(i-1,j-1,0)+d_f(i,j,0)=min(f(i-3-1,j,0),f(i-3-1,j,1),f(i,j,1)=f(i,j,1)=f(i-3-1,j-1,0)+di 이런 이동은 말할 필요가 없다.
그러나 이런 복잡도는 O(nk)O(nk)O(nk)로 넘을 수 없다.해결 방법은 방법에 따라 wqs 2점 최적화를 써서 jjj의 1차원을 낮추면 된다.
#include
#include
#include
#include
template <typename T> inline void read(T& x) {
int f = 0, c = getchar(); x = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
if (f) x = -x;
}
template <typename T, typename... Args>
inline void read(T& x, Args&... args) {
read(x); read(args...);
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
template <typename T> inline void writeln(T x) { write(x); puts(""); }
template <typename T> inline bool chkmin(T& x, const T& y) { return y < x ? (x = y, true) : false; }
template <typename T> inline bool chkmax(T& x, const T& y) { return x < y ? (x = y, true) : false; }
typedef long long LL;
const int maxn = 1e5 + 207;
const LL inf = 1e10;
int n, K;
LL d[maxn];
// f[i][0] = min(f[i-1][0], f[i-1][1])
// f[i][1] = f[i-1][0] + d[i] - mid
struct Data {
int cnt;
LL f;
Data() : cnt(0), f(0) {}
Data(int a, LL b) : cnt(a), f(b) {}
};
Data dp[maxn][2];
inline bool operator<(const Data &lhs, const Data &rhs) {
return lhs.f < rhs.f || (lhs.f == rhs.f && lhs.cnt < rhs.cnt);
}
inline void solve(LL mid) {
for (int i = 0; i <= n; ++i)
dp[i][0] = dp[i][1] = Data();
for (int i = 1; i <= n; ++i) {
dp[i][0] = std::min(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] = Data(dp[i - 1][0].cnt + 1, dp[i - 1][0].f + d[i] - mid);
}
}
int main() {
read(n, K);
for (int i = 0; i < n; ++i) read(d[i]);
for (int i = n - 1; i; --i) d[i] -= d[i - 1];
d[0] = 0; --n;
LL left = 0, right = inf, ans;
while (left <= right) {
LL mid = (left + right) >> 1;
solve(mid);
const Data &mn = std::min(dp[n][0], dp[n][1]);
if (mn.cnt <= K)
ans = mn.f + mid * K, left = mid + 1;
else right = mid - 1;
}
writeln(ans);
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【경쟁 프로 전형적인 90문】008의 해설(python)의 해설 기사입니다. 해설의 이미지를 봐도 모르는 (이해력이 부족한) 것이 많이 있었으므로, 나중에 다시 풀었을 때에 확인할 수 있도록 정리했습니다. ※순차적으로, 모든 문제의 해설 기사를 들어갈 예정입니다. 문자열...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.