Codeforces Round #210 (Div. 1) B. Levko and Array (二分+dp)

本文详细解析了 CodeForces 平台上的 360B 题目,通过动态规划和二分查找的结合,解决了一个关于数组调整的最优化问题。介绍了如何在限制条件下,通过调整数组元素来最小化相邻元素间的最大差值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://codeforces.com/problemset/problem/360/B

题目大意:

       给你一个数组a含n个整数,现在你可以任意改变k个数字,最小化最大值a[i+1] - a[i] (1 <= i <= n-1)。1 <= k <= n <= 2000。

解题思路:

        一般最小化最大值可以想到二分,但是怎么检验最小化的最大值是个难办的问题,因为你又不能暴力枚举。看到n和k的范围那么小,能不能用dp检验呢?答案是可以的。考虑dp[i]表示在a[i]不变的情况下,前i个数已经调整好,所需要调整的数的个数。可得转移方程为dp[i] = min(dp[i], dp[j] + (i-j-1)), (1 <= j < i)。(i-j-1)表示a[i]和a[j]之间有(i-j-1)个数,而且这些数都要得到调整。转移需要的条件是(i-j)*k <= abs(a[i] - a[j]), k是需要检验的答案。需要这个条件的原因是a[i]和a[j]之间有(i - j)个间隔,那么a[i]和a[j]在这个检验答案中最多允许相差(i-j) * k,否则无论怎么调整a[i]和a[j]的之间数都无法得出答案的,也就是无法转移状态。

代码如下:

# include <bits/stdc++.h>

using namespace std;

typedef long long ll;
ll n, k;
ll a[2005], dp[2005];

bool check(ll mid){
    for(int i = 1; i <= n; ++i){
        dp[i] = i-1;
        for(int j = 1; j < i; ++j){
            if(mid*(i-j) >= abs(a[i] - a[j]))
                dp[i] = min(dp[i], dp[j] + i - j - 1);
        }
        if(k - (n-i) >= dp[i])  return true;
    }
    return false;
}

int main(){
    std::ios::sync_with_stdio(false);
    while(cin >> n >> k){
        ll l = 0, r = 0;
        for(int i = 1; i <= n; ++i){
            cin >> a[i];
            r = max(r, abs(a[i] - a[i-1]));
        }

        ll ans = r;
        while(l <= r){  //注意加等号!!!
            ll mid = (l+r) / 2;
            if(check(mid)){
                r = mid-1;
                ans = mid;
            } else {
                ans = mid+1;
                l = mid+1;
            }
        }
        cout << ans << endl;
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值