题意:给定数列{an},任意改动其中至多k项,求相邻两项差的绝对值的最大值的最小值。
思路:二分答案(二分的区间可以优化),对于某一个二分值mid,采用DP检验其可行性。
设dp[i]表示考虑前i个数,且第i个数不变,至少需要改多少个才能使得答案不大于mid。
那么考虑下一个不变的数是a[j],则a[i+1]~a[j-1]这些数可以任意改变,前提是abs(a[i]-a[j])<=(j-i)*mid。
思路:二分答案(二分的区间可以优化),对于某一个二分值mid,采用DP检验其可行性。
设dp[i]表示考虑前i个数,且第i个数不变,至少需要改多少个才能使得答案不大于mid。
那么考虑下一个不变的数是a[j],则a[i+1]~a[j-1]这些数可以任意改变,前提是abs(a[i]-a[j])<=(j-i)*mid。
接下来枚举最后一个不变的数到底是哪个,ans=min(ans,dp[i]+n-i)。只要ans<=k就可行,否则不可行
周赛的题目 mark下
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<ctime>
#define maxn 500
#define inf 3000
#define ll long long
using namespace std;
ll n,k;
ll a[maxn+5];
ll dp[maxn+5];
bool check(ll mid) {
for(int i=1; i<=n; i++) dp[i]=i-1;
for(int i=1; i<=n; i++) {
for(int j=i+1; j<=n; j++) {
if(abs(a[j]-a[i])<=(j-i)*mid) {
dp[j]=min(dp[j],dp[i]+(j-i-1));
}
}
}
ll ans=inf;
for(int i=1; i<=n; i++) {
ans=min(ans,dp[i]+(n-i));
}
return ans<=k;
}
ll solve() {
ll left=-1,right=2000000000;
while(left+1<right) {
ll mid=(left+right)>>1;
if(check(mid)) {
right=mid;
} else {
left=mid;
}
}
return right;
}
int main() {
int T;
scanf("%d",&T);
for(int kase=1; kase<=T; kase++) {
scanf("%lld%lld",&n,&k);
for(int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
}
printf("%lld\n",solve());
}
return 0;
}