CF360B Levko and Array
题目链接:
洛谷
Codeforces
Solution
二分好题。
答案有单调性,首先二分。
现在问题转化成如何判断最少要改几个,使用 dp,设 \(f(i)\) 表示第 \(i\) 个不改,前 \(i\) 个最多几个不改,转移方程为:
\[f(i)=\max(f(j)+1)
\]
这个转移方程成立,当且仅当第 \(i\) 个和第 \(j\) 个可以同时不选,即 \(|a_i-a_j|\le x*(i-j)\and j<i\),表示的是两者之差小于最大差,所以不选的加 \(1\)。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
const int N=2007;
int f[N],a[N],n,k;
bool check(int x)
{
for(int i=1;i<=n;i++)f[i]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<i;j++)
if(abs(a[i]-a[j])<=x*(i-j))f[i]=max(f[j]+1,f[i]);
}
for(int i=1;i<=n;i++)
if(i-f[i]+n-i<=k)return 1;//前面最少改的加上后面都改
return 0;
}
main()
{
read(n);read(k);
for(int i=1;i<=n;i++)
read(a[i]);
int l=0,r=2e9,ans;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans;
return 0;
}