CF360B Levko and Array (二分查找+DP)
链接:CF360B
题目:
大意:在数组a中改变任意k个元素的值,使得到的的值最小。
题解:
二分答案,用dp检查可不可行。
dp[j]表示a[0]~a[j]中,a[j]不变时所要改变的数的数量。
1 bool check(ll x) 2 { 3 int i,j; 4 for(i=0; i<n; i++) 5 dp[i]=i; 6 for(i=0; i<n; i++) 7 for(j=i+1; j<n; j++) 8 if(abs(a[i]-a[j])<=(j-i)*x) dp[j]=min(dp[j],dp[i]+j-i-1); 9 for(i=0; i<n; i++) 10 if (dp[i]+n-i-1 <= k) 11 return true; 12 return false; 13 }
check如上,转移方程时假设a[i]和a[j]之间的数都要改变,那个if是判断是否全部改变了,达成一个超碉的阶梯状,a[i]和a[j]还是差的太远的话就不转移了。
然后后面算的dp[i]+n-i-1是a[i]不变,后面的元素全变的需要变的元素数量。只要有一种方案行,就行。
代码:
1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 #define ll __int64 9 10 int a[2222]; 11 int dp[2222]; 12 int n,k; 13 bool check(ll x) 14 { 15 int i,j; 16 for(i=0; i<n; i++) 17 dp[i]=i; 18 for(i=0; i<n; i++) 19 for(j=i+1; j<n; j++) 20 if(abs(a[i]-a[j])<=(j-i)*x) dp[j]=min(dp[j],dp[i]+j-i-1); 21 for(i=0; i<n; i++) 22 if (dp[i]+n-i-1 <= k) 23 return true; 24 return false; 25 } 26 27 int main() 28 { 29 int i; 30 ll mid,l,r; 31 while(scanf("%d%d",&n,&k)!=EOF) 32 { 33 for(i=0; i<n; i++) 34 scanf("%d",&a[i]); 35 l=0; 36 r=2000000000; 37 while(l<=r) 38 { 39 mid=(l+r)>>1; 40 //cout<<l<<'<'<<mid<<'<'<<r<<endl; 41 if(check(mid)) r=mid-1; 42 else l=mid+1; 43 } 44 printf("%I64d\n",l); 45 } 46 return 0; 47 }