[海豹海边爆]Daimayuan463

原题链接:饿饿 饭饭 - 题目 - Daimayuan Online Judge

解题思路:首先,如果打饭数k与总饥饿一致,则直接结束,因为没有人饿着,总饥饿也没有小于打饭数。而如果总饥饿小于打饭数,直接输出-1。这是两个特判,可以节省时间。

如果不属于上方的特判,是正常情况,可以按照以下步骤模拟:

第一步,选取最小的饭量,将其乘以总人数,如果小于打饭量k,则k减去该值,然后总人数减去饭量最小的人数得到剩余人数。然后剩余人数乘以第二小的饭量。如此循环,直到剩余人数乘以当时的饭量大于剩余k时,记录当前饭量为maxx,进入下一步。模拟的是所有人进行了喂饭,吃饱的离开。

第二步,如果剩余k除以剩余人数大于1,则所有剩余人员的饭量减去该商。模拟的是所有人又进行了完整的喂饭且无人吃饱。

第三步,给剩余的每个人喂一次,看到哪个人为止,喂到饭的饭量-1。模拟的是不完整的喂饭,即最后一轮。

第四步,从上一步最后一个被喂的后一个人开始查询,如果剩余饭量大于maxx(因为maxx记录了第一步中剩下每个人实际吃了多少,大于maxx代表实际没吃饱),则输出序号,直到循环到上一步最后一个被喂的人为止。

AC代码:

#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100010],maxx=0,zrs,bk,bs;
//n,k,a为题目本意,maxx为第一部中吃的饭,zrs储存剩余人数,bk储存减去总饭量的k,用于特判,bs记录从谁结束最后一口饭 
set<long long> s;//记录有哪些饭量 
unordered_map<long long,int> tong;//记录每个饭量的人数 
int main(){
	cin>>n>>k;//输入 
    zrs=n,bk=k;
	for(int i=0;i<n;i++){
		scanf("%lld",&a[i]);
		s.insert(a[i]);
		tong[a[i]]++;
        bk-=a[i];
	}
	
    if(bk>0){//特判
        cout<<-1;
        return 0;
    }
	if(bk==0) return 0; //特判
	
	for(auto i:s){//第一步 
		if((i-maxx)*zrs<=k){
            k-=(i-maxx)*zrs;
            zrs-=tong[i];
            maxx=i;
        }
        else break;
	}
	
    if(k>=zrs){//第二步 
        long long buffer;
        buffer=k/zrs;
        for(int i=0;i<n;i++){
            if(a[i]>maxx) a[i]-=buffer;
        }
        k-=buffer*zrs;
    }
    
    for(int i=0;k;i++,i%=n){//第三步 
        if(a[i]>maxx) a[i]--,k--;
        if(a[i]>maxx) bs=i;
    }
    
    for(int i=bs+1;i<n;i++){//第四步 
        if(a[i]>maxx) cout<<i+1<<' ';
    }
    for(int i=0;i<=bs;i++){
        if(a[i]>maxx) cout<<i+1<<' ';
    }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值