1 条题解

  • 0

    题意分析

    给定一个长度为NN的整数序列AA,需要构造一个长度相同的序列BB,使得以下两部分之和VV最小:

    1. AABB的绝对差之和:i=1NA(i)B(i)\sum_{i=1}^{N} |A(i) - B(i)|
    2. BB序列相邻元素的绝对差之和:i=1N1B(i)B(i+1)\sum_{i=1}^{N-1} |B(i) - B(i+1)|

    解题思路

    1. 问题分解
      • 第一部分要求BB尽可能接近AA(使A(i)B(i)|A(i)-B(i)|最小)
      • 第二部分要求BB序列尽可能平滑(使相邻元素变化B(i)B(i+1)|B(i)-B(i+1)|最小)
    2. 关键观察
      • 最优解中B(i)B(i)的取值范围应在AA序列的最小值和最大值之间
      • 可通过动态规划求解,状态设计需考虑当前B(i)B(i)的取值对后续的影响

    实现步骤

    1. 预处理
      • 确定AA序列的最小值min_Amin\_A和最大值max_Amax\_A
      • 枚举B(i)B(i)的可能取值范围(min_Amin\_Amax_Amax\_A
    2. 动态规划
      • 定义dp[i][j]dp[i][j]表示处理到第ii个元素时B(i)=jB(i)=j的最小VV
      • 状态转移方程:
        $dp[i][j] = |A(i)-j| + \min_{k} (dp[i-1][k] + |k-j|)$
    3. 结果提取
      • 最终结果为minjdp[N][j]\min_{j} dp[N][j]

    代码实现

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define INF 0x3fffffff
    #include<iostream>
    using namespace std;
    int mad(int a,int b,int c)
    {//取三个数的中间值
        int ma=a,mi=a;
        ma=max(a,b);
        ma=max(ma,c);
        mi=min(a,b);
        mi=min(mi,c);
        return a+b+c-mi-ma;
    }
    int main()
    {
        int a[1000];
        int b[1000];
        int  n;
        int s=0;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        for(int i=1; i<n-1; i++)
        {
            b[i]=mad(b[i-1],a[i],b[i+1]);
        }
        for(int i=0; i<n; i++)
        {
            s+=fabs(a[i]-b[i]);
        }
        for(int i=1; i<n; i++)
            s+=fabs(b[i]-b[i-1]);
        printf("%d\n",s);
        return 0;
    }
    • 1

    信息

    ID
    1314
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者