2022ICPC南京站D

1:题意

给你一个序列要求你进行一次操作,选一个位置i从他开始往后加数直到加到第i+m-1个,加的值成等差求操作完后的第k大的数

2:思路

1):二分答案

二分找到第k大的值

2):差分

check里面,枚举每一个数看他是否大于mid,记录为num,小于的判断他是否+等差最后一位小于mid,小于直接跳过,大于则判断他可以在那一个位置,然后把他这个区间表示出来,即贡献度,再前缀和一下就可以了

代码

点击查看代码
#include <bits/stdc++.h>

using namespace std;

#define int long long
const int N = 1e6 + 10;
typedef long long ll;
int a[N];
int n,m,k,c,d;
bool check(int mid)
{
	vector<int>f(n+2,0);
	int num = 0;
	for(int i = 1;i <= n;i ++)
	{
		if(a[i] >= mid)
		num++;
		else if(a[i] + c + d*(m-1) < mid )
		continue;
		else
		{
			int cnt = 0;
			if(d)
			{
				int tmp = a[i]+c;
				cnt = (mid - tmp + d - 1)/d;
				cnt = max(0LL,cnt);
			}
			f[max(0LL,(i-m+1))]++;
			f[min(n+1,max(0LL,i - cnt+1))]--;
		}
	}
	
	int mx = 0;
	for(int i = 1;i <= n;i ++)
	{
		f[i] += f[i-1];
		mx = max(mx,f[i]);
	}
	if(mx + num >= k)
	return true;
	else
	return false;
}

void solve()
{
	cin >> n >> k >> m >> c >> d;
	
	for(int i = 1;i <= n;i ++)
	cin >> a[i];
	
	int l = 0,r = 1e18;
	while(l < r)
	{
		int mid = (l+r+1)/2;
		if(check(mid))
		l = mid;
		else 
		r = mid - 1;
		
		//cout << l << ' ' << r << '\n';
	}
	
	cout << l << '\n';
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	solve();
}
posted @ 2023-09-10 22:00  清初  阅读(91)  评论(0)    收藏  举报