NC224938 加减
题目
题目描述
小红拿到了一个长度为 的数组。她每次操作可以让某个数加 或者某个数减 。
小红最多能进行 次操作。她希望操作结束后,该数组出现次数最多的元素次数尽可能多。
你能求出这个最大的次数吗?
输入描述
第一行两个正整数 和
第二行有 个正整数
输出描述
不超过 次操作之后,数组中可能出现最多次数元素的次数。
示例1
输入
5 3 6 3 20 8 1
输出
2
说明
共 3 次操作如下:
第一个数加一。
第二个数加一。
第四个数减一。
数组变成了 ,共有 个相同的数: 。
可以证明, 为最优解。另外,此上操作并不是唯一的操作。
题解
知识点:二分,前缀和,双指针,枚举。
排序好数列中,若要构成相同的数字,那么构成子串是同样情况下花费次数最少的,因此考虑遍历所有左端点,且每次左移左端点不需要回调右端点,因为左移端点后区间长度一定小于等于原来合法最大值,就算区间内有合法右端点但也不可能更新最大值,所以不考虑回调。(尺取法)
在同一个区间所有数字离中位数最近,消耗次数最小,偶数区间中间两个数字选取等价。(二分)
为了方便计算某区间的消耗,需要预处理出排序好后的前缀和。(前缀和)
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; ll a[100007],s[100007]; int main(){ std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); ll n,k; cin>>n>>k; for(int i = 1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+1+n); for(int i = 1;i<=n;i++){ s[i] = a[i] + s[i-1]; } int l = 1,r = 1; int ans = 0; ///排序好数列中,若要构成相同的数字,那么构成子串是同样情况下花费次数最少的。 ///因此考虑遍历所有左端点,且每次左移左端点不需要回调右端点,因为左移端点后区间长度一定小于等于原来合法最大值,就算区间内有合法右端点但也不可能更新最大值,所以不考虑回调。 while(l<=n){ while(r<=n){ int mid = l+r>>1;///在同一个区间所有数字离中位数最近,消耗次数最小,偶数区间中间两个数字选取等价 if((mid-l)*a[mid]-(s[mid-1]-s[l-1]) + (s[r]-s[mid]) - (r-mid)*a[mid]>k) break; r++; } ans = max(ans,r-l); l++; } cout<<ans<<'\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16249479.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)