zoukankan      html  css  js  c++  java
  • Codeforces 571B Minimization:dp + 贪心【前后相消】

    题目链接:http://codeforces.com/problemset/problem/571/B

    题意:

      给你一个长度为n的数列a[i]。

      现在你可以随意改变数字的位置,问你 ∑| a[i] - a[i+k] | 的最小值(1 <= i <= n-k)。

    题解:

      将a[i]拆成若干个子序列s[j],子序列中相邻两数在a[i]中的距离为k。

      此时原式 = ∑(子序列s[j]内部之差的和)

     

      显然,要想使子序列s[j]内部之差的和尽可能小,子序列s[j]内部一定为升序。

      显然,要想使 ∑(子序列s[j]内部之差的和)尽可能小,所有子序列s[j]一定是由a[i]升序排序后分割而来。

      可以发现,拆出的子序列中:

        有 n2 = n%k 个子序列长度为 l1 = n/k+1

        有 n1 = k-n%k 个子序列长度为 l2 = n/k

      此时:

        原式 = ∑ (s[2]-s[1]+s[3]-s[2]+s[4]-s[3]...)

      前后相消之后就是:

        原式 = ∑ (s[i][end] - s[i][1])

      此时题目就变成了:

        先将a[i]排序,然后将a[i]分割成n1个长为l1的子串,以及n2个长为l2的子串。

        让你使得 ∑ (s[i][end] - s[i][1])最小。

      表示状态:

        dp[i][j]

        表示从头开始分割,已经分割出了i个长为l1的子串,以及j个长为l2的子串。

      找出答案:

        ans = dp[n1][n2]

      如何转移:

        if(i) dp[i][j] = min(dp[i][j], dp[i-1][j]+a[start1]-a[end1])

        if(j) dp[i][j] = min(dp[i][j], dp[i][j-1]+a[start2]-a[end2])

        start1/2, end1/2分别是新分割出的子串的首位与末尾。

      边界条件:

        dp[0][0] = 0

        others = INF

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <algorithm>
     5 #define MAX_N 300005
     6 #define MAX_S 5005
     7 
     8 using namespace std;
     9 
    10 int n,k;
    11 int a[MAX_N];
    12 long long dp[MAX_S][MAX_S];
    13 
    14 int main()
    15 {
    16     cin>>n>>k;
    17     for(int i=1;i<=n;i++) cin>>a[i];
    18     sort(a+1,a+n+1);
    19     int n1=n%k,n2=k-n%k;
    20     int l1=n/k+1,l2=n/k;
    21     memset(dp,0x3f,sizeof(dp));
    22     dp[0][0]=0;
    23     for(int i=0;i<=n1;i++)
    24     {
    25         for(int j=0;j<=n2;j++)
    26         {
    27             if(i) dp[i][j]=min(dp[i][j],dp[i-1][j]+a[i*l1+j*l2]-a[(i-1)*l1+j*l2+1]);
    28             if(j) dp[i][j]=min(dp[i][j],dp[i][j-1]+a[i*l1+j*l2]-a[i*l1+(j-1)*l2+1]);
    29         }
    30     }
    31     cout<<dp[n1][n2]<<endl;
    32 }
  • 相关阅读:
    jvisualvm工具使用
    Java四种引用包括强引用,软引用,弱引用,虚引用。
    <实战> 通过分析Heap Dump 来了解 Memory Leak ,Retained Heap,Shallow Heap
    什么是GC Roots
    Memory Analyzer tool(MAT)分析内存泄漏---理解Retained Heap、Shallow Heap、GC Root
    JDK自带工具之问题排查场景示例
    websocket协议握手详解
    ssh 登陆服务器原理
    新版本macos无法安装mysql-python包
    如何将多个小值存储进一个值中
  • 原文地址:https://www.cnblogs.com/Leohh/p/8214560.html
Copyright © 2011-2022 走看看