专栏文章

CF760B

CF760B题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miorwb45
此快照首次捕获于
2025/12/03 00:08
3 个月前
此快照最后确认于
2025/12/03 00:08
3 个月前
查看原文
你好。

题面

mm 个物品给排成一排的 nn 人,求第 kk 个人可以拿到的最大物品数,要求相邻的人物品数相差不超过 11,且每个人都有物品。

题解

二分第 kk 个人可以拿到的物品数 xx
若第 kk 个人拿到 xx 个物品,则可以构造出一种方案,使得这一排人拿到的物品数最小。
如果第 ii 个人拿到 jj 个物品,那么第 i1i-1i+1i+1 人可以拿到 j1j-1jjj+1j+1 个物品。
由此我们可以这样构造:第 kk 个人拿到的最多,然后区间 [k,n][k,n]kknn 递减,区间 [1,k][1,k]kk11 递减,当递减到 11 时重复。
显而易见这样构造可以使得拿到物品数最小。
设这个最小值为 ss
sms \le mss 在所有满足 sms \le m 中的 ss 最大时,xx 也达到合法最大。
然后就可以这样二分了。
时间复杂度 O(logm)O(\log m)

代码

CPP
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,k;
ll l,r;
bool check(ll x) {
	ll b,c;
	if(x-(n-k)<=0) b=x*(x-1)/2+1-(x-(n-k));
	else b=(x-1+x-(n-k))*(n-k)/2;
	if(x-(k-1)<=0) c=x*(x-1)/2+1-(x-(k-1));
	else c=(x-1+x-(k-1))*(k-1)/2;
  //等差数列求和公式来求[1,k-1]和[k+1,n]贡献
	return b+c+x<=m;
}
int main() {
	scanf("%lld%lld%lld",&n,&m,&k);
	l=1,r=m;
	while(l<r) {
		int mid=(l+r+1)/2;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	printf("%lld",l);
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...