CF360B Levko and Array(DP+二分答案)

题意:

一个长度为n的序列a[i],可以将其中k个数的值任意改变,要求最小化相邻两个数绝对值之差的最大值

题解:

 /*
 *author: zlc
 *zucc_acm_lab
 *just do it
 */
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int inf=1e9;
const int maxn=2e5+100;
inline int read () {int x=0;int f=1;char ch=getchar();while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;}
ll qpow (ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int n,k;
int a[2005];
int dp[2005];
//dp[i]表示前i个值中相邻两个数绝对值差不超过mid且第i个值不变,最少的改变次数 
//只有当a[i]和a[j]的差不超过mid*(i-j)时才有可能通过改变i~j的元素使得合法
//最后存在某个数使得dp[i]+n-k<=k,说明mid值合法 
int check (ll mid) {
    dp[1]=0;
    for (int i=2;i<=n;i++) {
        dp[i]=i-1;
        for (int j=1;j<i;j++) {
            if (abs(a[i]-a[j])<=(ll)mid*(i-j))
                dp[i]=min(dp[i],dp[j]+i-j-1);
        }
    }
    if (dp[n]<=k) return 1;
    for (int i=1;i<=n;i++) if (dp[i]+n-i<=k) return 1;
    return 0;
}
int main () {
    ll ans=0;
    n=read(),k=read();
    for (int i=1;i<=n;i++) a[i]=read();
    ll l=0,r=2e9;
    while (l<=r) {
        ll mid=(l+r)>>1;
        if (check(mid)) {
            ans=mid;
            r=mid-1;
        }
        else
            l=mid+1;
    }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zhanglichen/p/13653286.html