1. 程式人生 > 其它 >函式最值2

函式最值2

目錄

題目描述

對於一個數組 \(A\) 定義 \(F(A)=max{abs(a[i]−a[i+1])};\) 給定一個數組,最多修改其中 \(k\) 個元素,只能把數修改成整數,求 \(F(A)\) 的最小值。

題目分析

這題很容易想到是二分,二分 \(F(A)\)
check 是用 dp 。

  • 狀態
    mid:相鄰兩數的差不超過 \(mid\)
    i:表示搜到第 \(i\)
    j:表示 \(1~i-1\)的一個數。
    dp[i]:表示 \(i\) 不改變的最小修改的元素個數。
  • 初始化
    很容易想到dp[i]=i-1
  • 轉移
    如果\(|a[i]-a[j]|\)小於相鄰兩數的差的最大值*差的數量,
    那就改i~j中間的數使差值平均,
    否則改了也不滿足條件。
    所以狀態轉移方程就是:
if(abs(a[i]-a[j])<=x*(i-j))
    dp[i]=min(dp[i],dp[j]+i-j-1);

要修改的個數就是sum=min(dp[i]+n-i);(假設後面都要改)

題目程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,k,a[N],dp[N];
bool check(int x)
{
	int sum=n+1;
	for(int i=1;i<=n;i++)
	{
		dp[i]=i-1;
		for(int j=1;j<i;j++)
			if(abs(a[i]-a[j])<=x*(i-j))
				dp[i]=min(dp[i],dp[j]+i-j-1);
		sum=min(sum,dp[i]+n-i);
	}
	return sum<=k;
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int l=0,r=1e9;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(check(mid))r=mid-1;
		else l=mid+1;
	}
	cout<<l;
	return 0;
}