加减 (双指针+前缀和)

本文探讨了在给定序列中通过不超过k次加一减一操作,最大化相同数值的数量的算法。通过维护区间并寻找中位数附近的平衡,作者提供了一个O(n log n)复杂度的解决方案。讨论了可能存在的问题并给出C++代码实现。
摘要由CSDN通过智能技术生成

题目:给定一个长度为n的序列,进行加一减一的操作不超过k次,最多有多少个数相同?

思路:维护若干个区间,每个区间都能在k步内变为同一个数,求最长的区间。尽量往中位数靠。

两个问题:感觉有点像 O(n^2) ;而且偶数的时候,中位数默认是中间左边的数。

#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long 
const int N = 1e5 + 10;

ll n, k, a[N], s[N];

bool judge(ll mid, int i, int j)
{
	ll tmp = a[mid];
	
	ll l = (mid-i) * tmp - (s[mid-1]-s[i-1]); // 从中位数到左端点 * 中位数与他们的差值 - 原本的数 = 左边需要操作的步数
	
	ll r = s[j]-s[mid-1] - (j-mid+1) * tmp;  //  右边也是同样的道理
	
	if(l + r <= k ) return true;
	
	return false;
}


int main()
{
	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] = s[i-1] + a[i];
	
	int ans;
	
	for(int i = 1, j = 1; i <= n; i++)
	{
		ll mid = (i+j+1) >> 1;
		
		while(j <= n and judge(mid, i, j))
		{
			j++;
			
			mid = (i+j+1) >> 1;
		}
		ans = max(ans, j-i);
	}
	cout << ans << endl;
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值