zoukankan      html  css  js  c++  java
  • POJ 3709 K-Anonymous Sequence (斜率优化DP)

    题意:有一个不递减的序列,现在要把这些数分成若干个部分,每部分不能少于m个数。每部分的权值为所有数减去该部分最小的数的和。求最小的总权值。

    析:状态方程很容易写出来,dp[i] = min{dp[j] + sum[i] - sum[j] - (i-j)*a[j+1] },然而这个复杂度是 O(n^2)的肯定要TLE,

    用斜率进行优化,维护一个下凸曲线,注意这个题是有个限制就是至少有要m个是连续的,所以开始的位置是2*m,想想为什么。

    代码如下:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #include <sstream>
    #define debug() puts("++++");
    #define gcd(a, b) __gcd(a, b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define freopenr freopen("in.txt", "r", stdin)
    #define freopenw freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e16;
    const double inf = 0x3f3f3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 500000 + 10;
    const int mod = 1e9 + 7;
    const int dr[] = {-1, 0, 1, 0};
    const int dc[] = {0, 1, 0, -1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline bool is_in(int r, int c){
      return r >= 0 && r < n && c >= 0 && c < m;
    }
    
    LL dp[maxn], sum[maxn];
    int a[maxn], q[maxn];
    
    LL getUP(int i, int j){
      return dp[i] - sum[i] + (LL)i*a[i+1] - (dp[j] - sum[j] + (LL)j*a[j+1]);
    }
    
    LL getDOWN(int i, int j){
      return a[i+1] - a[j+1];
    }
    
    LL getDP(int i, int j){
      return dp[j] + sum[i] - sum[j] - (LL)(i-j)*a[j+1];
    }
    
    int main(){
      int T;  cin >> T;
      while(T--){
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= n; ++i){
          scanf("%d", a+i);
          sum[i] = sum[i-1] + a[i];
        }
        int fro = 0, rear = 0;
        q[++rear] = m;
        for(int i = m; i < 2*m; ++i)  dp[i] = sum[i] - i * a[1];
        for(int i = m * 2; i <= n; ++i){  // notice
          while(fro+1 < rear && getUP(q[fro+2], q[fro+1]) <= i*getDOWN(q[fro+2], q[fro+1]))  ++fro;
          dp[i] = getDP(i, q[fro+1]);
          int k = i - m + 1;
          while(fro+1 < rear && getUP(k, q[rear])*getDOWN(k, q[rear-1]) <= getUP(k, q[rear-1])*getDOWN(k, q[rear]))  --rear;
          q[++rear] = k;
        }
        printf("%I64d
    ", dp[n]);
      }
      return 0;
    }
    

      

  • 相关阅读:
    HDU 1114 Piggy-Bank
    HDU 2955 Robberies
    NTOJ 290 动物统计(加强版)
    POJ 3624 Charm Bracelet
    HDU 2602 Bone Collector
    POJ 1523 SPF(无向图割顶)
    HDU 5311 Hidden String
    HDU 1421 搬寝室
    HDU 1058 Humble Numbers
    POJ 3259 Wormholes(spfa判负环)
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/7327755.html
Copyright © 2011-2022 走看看