[关闭]
@Livingston 2021-05-04T04:00:02.000000Z 字数 923 阅读 616

[JZOJ3154]「提高A组模拟」『单调队列』删数字

题解 单调队列

题目

给你一个N 个数组成的序列V,要你删除其中K 个数,M 表示剩下的数字中任意两个数的差值的最大值,m 表示最小差值,要你计算删除K 个数后,M+m的最小值。

的数据

题解

这次GDOI有类似的一道题:P7514 卡牌游戏

首先将序列V排序,有个显然的结论是最后留下来的一定是一段连续的长度为的子序列,证明如下

(V单调不下降)

现有区间为,如果不删去或者,而是从中选择一个删去,那么差值的最大值变大,最小值不会变小,因此答案更劣

那么这个题目就简单了,最大差值肯定是序列的首尾两端的差,求最小差值可以用单调队列来做

Code

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define N 1000005
  4. #define ll long long
  5. #define inf 9999999999999
  6. using namespace std;
  7. struct node
  8. {
  9. int val,id;
  10. }q[N];
  11. ll n,k,h,t,ans;
  12. ll a[N];
  13. int main()
  14. {
  15. scanf("%lld%lld",&n,&k);k=n-k;
  16. for (int i=1;i<=n;++i)
  17. scanf("%lld",&a[i]);
  18. sort(a+1,a+n+1);
  19. h=1;t=0;
  20. a[0]=-inf;ans=inf;
  21. for (int i=2;i<k;++i)
  22. {
  23. while (h<=t&&q[t].val>=a[i]-a[i-1]) --t;
  24. q[++t].val=a[i]-a[i-1];q[t].id=i;
  25. }
  26. for (int i=k;i<=n;++i)
  27. {
  28. while (h<=t&&q[t].val>=a[i]-a[i-1]) --t;
  29. q[++t].val=a[i]-a[i-1];q[t].id=i;
  30. while (h<=t&&q[h].id+k<=i) ++h;
  31. ans=min(ans,q[h].val+a[i]-a[i-k+1]);
  32. }
  33. printf("%lld\n",ans);
  34. return 0;
  35. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注