• 线性dp,优化记录,273. 分级


    273. 分级

    273. 分级 - AcWing题库

    给定长度为 N 的序列 A,构造一个长度为 N 的序列 B,满足:

    1. B 非严格单调,即 B1≤B2≤…≤BN 或 B1≥B2≥…≥BN。
    2. 最小化 S=∑Ni=1|Ai−Bi|。

    只需要求出这个最小值 S。

    输入格式

    第一行包含一个整数 N。

    接下来 N 行,每行包含一个整数 Ai。

    输出格式

    输出一个整数,表示最小 S 值。

    数据范围

    1≤N≤2000
    0≤Ai≤106

    输入样例:
    1. 7
    2. 1
    3. 3
    4. 2
    5. 4
    6. 5
    7. 3
    8. 9
    输出样例:
    3

    解析

    这是一道结论题,在做这道题之前先要知道一个结论:

    在满足S最小化的前提下,一定会存在一种构造序列B的方案,使得B中的数值都在A中出现过

     所以我们可以构造一种B序列,使得B序列的数从排过序的A中选

    DP的核心思想是用集合来表示一类方案,然后从集合的维度来考虑状态之间的递推关系。

    受上述性质启发,状态表示为:

    f[i][j]:前 i 个A 中,第 i 个A与排序后的第 j 个A中选取第 j 个相减所得的最小值

    可以发现这是一个不重不漏的集合划分方式

    状态转移方程为:

    f[i][j]=min(f[i-1][j-k])+abs(A[i]-SA[j])

    初始化为 f =0x3f , f[0]=0

    i: 1到n

    j:1到n

    k: 1到j

    这显然会超时,所以我们优化一下

    将状态转移方程展开:

    f[i][j]=min(f[i-1][1],f[i-1][2],f[i-1][3]......f[i-1][j])+abs(A[i]-SA[j])

    所以我们可以用前缀处理的思想处理:min(f[i-1][1],f[i-1][2],f[i-1][3]......f[i-1][j])

    1. for (int i = 1; i <= n; i++) {
    2. mn = 0x3f3f3f3f;
    3. for (int j = 0; j <= n; j++) {
    4. mn = min(mn, f[i - 1][j]);
    5. f[i][j] = mn + abs(a[i] - sa[j]);
    6. }
    7. }

     所以代码就为

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. using namespace std;
    15. typedef long long LL;
    16. const int N = 2000 + 5;
    17. int n;
    18. int a[N],sa[N],f[N][N];
    19. int cmp(const int& a, const int& b) {
    20. return a > b;
    21. }
    22. int main() {
    23. scanf("%d", &n);
    24. for (int i = 1; i <= n; i++) {
    25. scanf("%d", &a[i]);
    26. sa[i] = a[i];
    27. }
    28. sort(sa + 1, sa + 1 + n);
    29. memset(f, 0x3f, sizeof(f));
    30. memset(f[0], 0, sizeof(f[0]));
    31. f[0][0] = 0;
    32. int mn = 0x3f3f3f3f;
    33. for (int i = 1; i <= n; i++) {
    34. mn = 0x3f3f3f3f;
    35. for (int j = 0; j <= n; j++) {
    36. mn = min(mn, f[i - 1][j]);
    37. f[i][j] = mn + abs(a[i] - sa[j]);
    38. }
    39. }
    40. int ans = 0x3f3f3f3f;
    41. for (int i = 1; i <= n; i++) {
    42. ans = min(ans, f[n][i]);
    43. }
    44. memset(f, 0x3f, sizeof(f));
    45. memset(f[0], 0, sizeof(f[0]));
    46. sort(sa + 1, sa + 1 + n, cmp);
    47. for (int i = 1; i <= n; i++) {
    48. mn = 0x3f3f3f3f;
    49. for (int j = 1; j <= n; j++) {
    50. mn = min(mn, f[i - 1][j]);
    51. f[i][j] = mn + abs(a[i] - sa[j]);
    52. }
    53. }
    54. for (int i = 1; i <= n; i++) {
    55. ans = min(ans, f[n][i]);
    56. }
    57. cout << ans << endl;
    58. return 0;
    59. }

    详细的证明: 

    AcWing 273. 分级 - AcWing

     

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. using namespace std;
    15. typedef long long LL;
    16. const int N = 2e3 + 5;
    17. int n;
    18. int a[N], b[N];
    19. int f[N][N];
    20. int cmp(const int& a, const int& b) {
    21. return a < b;
    22. }
    23. int dp() {
    24. for (int i = 1; i <= n; i++)
    25. b[i] = a[i];
    26. sort(b + 1, b + 1 + n, cmp);
    27. for (int i = 1; i <= n; i++) {
    28. int minv = 0x3f3f3f3f;
    29. for (int j = 1; j <= n; j++) {
    30. minv = min(minv, f[i-1][j]);
    31. f[i][j] = minv + abs(a[i] - b[j]);
    32. }
    33. }
    34. int ret = 0x3f3f3f3f;
    35. for (int i = 1; i <= n; i++)
    36. ret = min(ret, f[n][i]);
    37. return ret;
    38. }
    39. int main() {
    40. cin >> n;
    41. for (int i = 1; i <= n; i++)
    42. scanf("%d", &a[i]);
    43. int ans = dp();
    44. reverse(a + 1, a + 1 + n);
    45. ans = min(ans, dp());
    46. cout << ans << endl;
    47. return 0;
    48. }

  • 相关阅读:
    1 分钟 Serverless 搭建你的首个个人网站(完成就送猫超卡)
    JUC并发编程——8锁现象(基于狂神说的学习笔记)
    腾讯云Java后端15连问(6年经验):分布式+锁+MySQL+JVM+TCP
    解决 uniapp uni.getLocation 定位经纬度不准问题
    java反射详解及优化
    JavaScript数据类型转换
    [AI]Python中的Restful
    06 数列极限的概念
    centos oracle11g开启归档模式
    Python函数绘图与高等代数互融实例(三):设置X|Y轴文本标签|网格线
  • 原文地址:https://blog.csdn.net/Landing_on_Mars/article/details/132942623