EX. 游戏

一. 题意

给定n个数,每一次能使一个数减少A,其它数减少B。求最小的次数,使得所有数小于等于0.

二. 思路

         我们有一个很直白的贪心思路:

  1.   遍历序列,获取当前的最大数。
  2.   让最大数减A,其余减B。

        于是,0分的代码有啦!!!(连样例都不能过)

#include<iostream>
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define de(x) cout<<#x<<" "<<x<<endl;
using namespace std;

const int N=100000+100,INF=0x3f3f3f3f;
int n,A,B,ans,a[N];

signed main()
{
	cin>>n>>A>>B; A-=B;
	for(int i=1;i<=n;i++) cin>>a[i];
	
	while(1)
	{
		int* Tp=max_element(a+1,a+n+1);
		if(*Tp<=0) break;
		else
		{
			for(int i=1;i<=n;i++)
			{
				if(a[i]<=0) continue;
				a[i]-=B;
			}
			Tp-=A;
			ans++;
		}
	}
	
	cout<<ans<<endl;
	
	return 0;
}



        思考:为什么不对?

        发现:答案具有单调性。准确而言,如果次数k满足条件,那么>k的就一定能行。

        摊牌了,这题就是二分。

                我们每一次选取一个mid,判断当前的mid是否合法。

                        判断函数:

                                我们先遍历整个序列,将每个数减去 mid*B。如果此时的数还大于0,则补上若干个(B-A),时起值小于等于0,本次产生的花费就是减去的次数。

代码如下:

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;
int n,A,B,a[N],b[N];

bool ck(int mid)
{ 
	//先将原数组 copy 一遍,因为原数组不能被修改,修改的话只能新开个数组。 
	for(int i=1;i<=n;i++) b[i]=a[i];
	//res记录次数 
	int res=0;
	for(int i=1;i<=n;i++)
	{
		//判断当前是否要用A技能 
		if(b[i]<=B*mid) continue;
		
		b[i]-=B*mid;
		//如果要,则增加次数。 
		res+=ceil(b[i]*1.00/A);
	}
	if(res>mid) return false;
	else return true;
}

signed main()
{
	//读入加速 
	cin.sync_with_stdio(0);cin.tie(0);cout.sync_with_stdio(0);cout.tie(0);cin.exceptions(cin.failbit);cout.exceptions(cout.failbit);
	cin>>n>>A>>B;
	for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i];
	A-=B;
	
	//注意边界	 
	int int l=1,r=1e10;
	while(l<r)
	{
		int int mid=(l+r)/2;
		if(ck(mid)) r=mid;
		else l=mid+1;
	}
	
	cout<<l<<endl;
	
	return 0;
}

完结撒花!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值