0
点赞
收藏
分享

微信扫一扫

饿饿 饭饭


思路:

因为存在每对于所有的同学进行

打一次的饭的话

那么对于剩下的同学

他们仍然按照的原来的顺序排列(假如他们进行这一次打饭,他们都还需要打饭)

那么我们就只需要求

刚好要进行多少的轮次后

(刚好进行下一轮就大于k次打饭的次数)

再对剩余的同学进行模拟

但我们要注意有可能进行一定的轮次后

有的同学早已经吃完的然后离开

所有对于该情况需要特殊的讨论

对于剩下的还剩余吃饭次数的同学

我们将其分为两部分

第一部分是需要阿姨打饭并判断他们是否会离开的部分

第二部分是阿姨打饭已经打完了k次但仍然还在排队的部分


代码详解:

#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
ll a[(ll)1e5 + 3],c[(ll)1e5+3];
ll n, k, sum = 0;
ll sumrice(ll t)
{
	ll ans = 0;
	for (int i = 1; i <= n; i++)
		ans += min(a[i],t);//如果进行的人要吃的饭的次数小于t那么只需要吃
	return ans;
}

int main()
{
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld", &a[i]),
		sum += a[i];
	}
	if (k>sum) printf("-1");//当阿姨要打的次数大于所有人需要打的次数
	else
	{
		int l = 0, r = 1e9;
		while (l+1 < r)//二分找到刚好小于阿姨要打饭次数轮数
		{
			ll mid = (l + r) / 2;
			if (sumrice(mid) <= k)//当打饭的总次数小于k时使左边取中间值
				l = mid;
			else//右边取中间值
				r = mid;
		}
		int tsum = k - sumrice(l);//阿姨剩余要打饭的次数
		int t = 0;//记录经过l轮后还剩余的人总数
		for (int i = 1; i <= n; i++)
		{
			if (a[i] > l) c[++t] = i;//存剩下的人的编号
		}
		for (int i = tsum + 1; i <= t; i++)
			printf("%lld ",c[i]);//输出进行剩余tsum次后的人的编号
		for (int i = 1; i <= tsum; i++)
		{
			if (a[c[i]]!= l+1) printf("%lld ", c[i]);//如果该编号上的人要打的饭的次数刚好不等于1,那么
		}
	}
	return 0;
}

PS:不经一番寒彻骨,怎得梅花扑鼻香。

举报

相关推荐

0 条评论