CodeForces361D- Lekvo and Array(二分+dp)

Description
Levko has an array that consists of integers: a 1, a 2, … , a n. But he doesn’t like this array at all.
Levko thinks that the beauty of the array a directly depends on value c(a), which can be calculated by the formula:

在这里插入图片描述
The less value c(a) is, the more beautiful the array is.
It’s time to change the world and Levko is going to change his array for the better. To be exact, Levko wants to change the values of at most k array elements (it is allowed to replace the values by any integers). Of course, the changes should make the array as beautiful as possible.
Help Levko and calculate what minimum number c(a) he can reach.

Input
The first line contains two integers n and k (1 ≤ k ≤ n ≤ 2000). The second line contains space-separated integers a 1, a 2, … , a n ( - 10^ 9 ≤ a i ≤ 10^9).

Output
A single number — the minimum value of c(a) Levko can get.

Examples
Input
5 2
4 7 4 7 4
Output
0
Input
3 1
-100 0 100
Output
100
Input
6 3
1 2 3 7 8 9
Output
1

Note
In the first sample Levko can change the second and fourth elements and get array: 4, 4, 4, 4, 4.
In the third sample he can get array: 1, 2, 3, 4, 5, 6.

题意:
有一个长度为n的序列a,最多可以修改其中k个数的值,问修改后|a[i]-a[i-1]|的最大值最小是多少。

解法:
询问最大值最小是多少,首先想到二分差值,对每一个差值,进行dp。dp[i]表示a[i]不变,1~i-1位的数字至少要改变多少个才能都符合差值(因为不可能n个数字都需要改变,至少有一个固定)。枚举i,j遍历i-1到1,假如abs(a[i]-a[j])<=(i-j)*x,则dp[i]=min(dp[i],dp[j]+i-j-1)(a[i]与a[j]的差值小于i-j个差值,意味着a[j]不动,i到j之间所有的数都改变是一种可行的情况),最后判断dp[i]+n-i<=k(i往后所有的数都改变)是否成立,成立则返回true。若对于所有的i都不成立,返回false。
想法来自于https://www.cnblogs.com/TnT2333333/p/6833100.html。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
using namespace std;

long long n,k;
long long l,r,mmax=0;
long long a[2000+5],dp[2000+5];

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

int main()
{
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=2;i<=n;i++)mmax=max(mmax,abs(a[i]-a[i-1]));
    l=0;r=mmax;
    while(l<r){
        long long mid=(l+r)>>1;
        if(judge(mid))r=mid;else l=mid+1;
    }
    printf("%lld\n",l);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值