题目:
思路:
因为存在每对于所有的同学进行
打一次的饭的话
那么对于剩下的同学
他们仍然按照的原来的顺序排列(假如他们进行这一次打饭,他们都还需要打饭)
那么我们就只需要求
刚好要进行多少的轮次后
(刚好进行下一轮就大于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:不经一番寒彻骨,怎得梅花扑鼻香。