1. 程式人生 > >codeforces D. Levko and Array(二分加dp) 挺好的一個題

codeforces D. Levko and Array(二分加dp) 挺好的一個題

Note

In the first sample Levko can change the second and fourth elements and get array: 44444.

In the third sample he can get array: 123456.

題意:  給你n個數 你最多改變其中的k個數使得 兩個相鄰的數之間的差的絕對值最小。

思路:  二分 答案 (二分任意差的絕對值 看在mid的情況下是否符合情況 如果符合情況 那麼r=mid-1  否則l=mid+1 ) 

而在判斷的時候就要用到dp   dp[i] 表示在不改動a[i] 的情況下 前i個數需要改動的個數。

首先dp[1]=0;  那麼dp[i] =  ?  當然取決於前邊的情況  如果到j需要改動dp[j] 個數 那麼對於i 就有dp[i]=dp[j]+ i-j-1 ;  表示(j,i)的數都需要改變(開區間)  而改變的條件就是a[i]和

a[j] 的差值 小於等於(i-j)*mid     而是否符合條件只需要看dp[i]+n-i  是否小於等於k  

d程式碼: 

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define N 2005

using namespace std;

typedef long long ll;

const ll inf =1e15;

int n,k;
ll a[N];
ll dp[N];


int jud(ll num)
{
	memset(dp,inf,sizeof(dp));
	
	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])<=(i-j)*num)
			{
				dp[i]=min(dp[i],dp[j]+i-j-1);
			}
		}
		if(dp[i]+n-i<=k) return 1;
	}
	
	return 0;
}

int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	
	ll l ,r,mid;
	l=0; r=inf;
	ll ans=0;
	while(l<=r)
	{
		mid=(l+r)>>1;
		//printf(" mid : %lld\n",mid);
		if(jud(mid))
		{
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	
	printf("%lld\n",ans);
	return 0;
} 

/*

20 17
-5 -9 11 -7 -17 -8 0 -14 -20 -15 7 -13 0 -3 -14 0 9 -10 6 -19

5 1
-1000000000 1000000000 -1000000000 1000000000 -1000000000


*/