CodeForces 13C Sequence (DP)

1852 단어 dpcodeforces
제목 유형 DP
제목의 의미
n (1 < = n < = 5000) 개수의 서열을 제시합니다. 이 서열을 비체감으로 바꾸는 조작수는 최소한 얼마입니까?
매 조작은 n개 수 중의 어느 하나를 더하거나 줄일 수 있다
예를 들어 세 개의 수를 제시한다. 3, 2, 3. ->가장 좋은 방안은 두 번째 수를 1로 더하는 것이다. ->, 3, 3의 최소 조작수는 1이다.
문제풀이 방법
dp[i][j]-> 이전 i 개수가 j를 끝으로 하는 합법적인 서열로 변하는 데 필요한 최소 조작수
상태 이동 dp[i][j]=min(dp[i][j], dp[i-1][k]+코스트(원래 i번째 위치의 수가 j로 전환)(1<=k<=j)
즉, 전 i개수 j를 끝으로 (전 i-1개수가 j보다 작은 수로 끝난다)에서 옮길 수 있는데, 이때는 원래의 i개수에서 k로 옮기는 소모를 더해야 한다.
주의
입력한 수의 절대값은 1e9보다 작기 때문에 입력한 수를 이산화시켜야 하며, 점차적으로 추진할 때 스크롤 그룹으로 메모리를 최적화하여 MLE를 피할 수 있다
그리고 우리가 이동할 때마다 필요한 값이 j보다 작은 수의 최대 값이기 때문에 하나의 변수로 이 값을 저장하고 점차적으로 업데이트할 수 있습니다. 그렇지 않으면 TLE가
부록:
스탬프 -> 이산화란 무엇인가
학습 스크롤 배열
코드 참고. - 궁금한 거 있으면 댓글로 남겨주시면 빨리 답장해드릴게요.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

typedef long long LL;

const int MAXN = 5000 + 10;
const LL INF = 1LL<<62;
LL a[MAXN], b[MAXN];
LL dp[2][MAXN];

int main() {
  int n;
  while(cin>>n) {
    for( int i=0; i<n; i++ ) {
      cin>>a[i];
      b[i] = a[i];
    }
    sort(b, b + n);
    int tn = unique(b, b + n) - b; //        n   
    for( int i=0; i<tn; i++ ) dp[0][i] = abs(b[i] - a[0]), dp[1][i] = INF;
    int now = 0;
    for( int i=1; i<n; i++ ) {
      LL t_min = INF;
      for( int j=0; j<tn; j++ ) {
        t_min = min(t_min, dp[now][j]);
        dp[now^1][j] = min(dp[now^1][j], t_min + abs(b[j] - a[i]));
      }
      now ^= 1;
      for( int j=0; j<tn; j++ ) dp[now^1][j] = INF;
    }
    LL n_min = INF;
    for( int i=0; i<tn; i++ ) n_min = min(n_min, dp[now][i]);
    cout<<n_min<<endl;
  }
  return 0;
}

좋은 웹페이지 즐겨찾기