cf题目链接
北方高校第4次训练题目链接
题意:有n个数排成一列,现在你可以改变k个数的大小。问你max(|ai-ai+1|)的最小值是多少(a∈[0,2e10])(两个题目都保证n^2log复杂度可以过)
orz,这题先是在wannafly的每日中见过……当时没做……然后这次西工大负责的北方高校训练又出了这道题……看来我们也可以出原题了
思路:很容易想到二分答案,关键是怎么进行可行性判断……假设二分的答案为x,dp[i]表示第i个数不变,前i个数的最大差值不超过x。转移dp[i]=min(dp[i],dp[j]+i-j-1)(j<i),j要保证abs(a[i]-a[j])<=k*x(也就是i,j不变,改变中间的数)。这样,只要存在一个i使得dp[i]+n-i<=k就能判断x可行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> using namespace std; long long a[2002]; long long dp[2002]; long long INF=0x3f3f3f3f; int n,k; int judge(long long x) { for(int i=1;i<=n;i++)dp[i]=i-1; for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(abs(a[j]-a[i])<=(i-j)*x) { dp[i]=min(dp[j]+i-j-1,dp[i]); } int flag=0; for(int i=1;i<=n;i++) if(dp[i]+n-i<=k)flag=1; return flag; } int main() { int T; T=1; while(T--) { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%lld",a+i); long long l,r; l=0;r=2e9+1; long long ans; while(l<r-1) { long long mid=(l+r)/2; if(judge(mid)==1)r=mid; else l=mid+1; } if(judge(r-1))r=r-1; if(judge(l))r=l; printf("%lld\n",r); } return 0; }
|