(蓝桥真题)技能升级(二分+思维)

题目:

(蓝桥真题)技能升级(二分+思维)_第1张图片

样例输入: 

3 6
10 5
9 2
8 1

样例输出:

47

分析:如果这道题目模拟来做的话是非常好做的,因为我们每次都会选择当前可提升攻击力最多的技能进行升级,显然这样是最优的。那么这也就意味着我们每次选择的技能提升的攻击力是非递增的,于是我们显然可以对最后一次技能提升的攻击力进行二分,但是需要注意一点,就是假如我们最优情况下最后一次提升的攻击力是x,那么这并不代表我们下一次提升的攻击力最多是x-1,因为可能还存在使得提升攻击力也为x的技能,所以这一点是我们需要考虑的。但是我们可以确定的是提升攻击力大于x的技能都已经使用完了,所以我们可以先把所有提升攻击力大于x的技能所提升的攻击力算出来,并计算出使用技能的次数,那么剩下的就是提升攻击力等于x的技能了。用m-已经使用技能的次数,然后乘以x即可得到我们使用提升攻击力为x的技能所提升的总攻击力。可能这个时候会有小伙伴有疑问:有没有可能没有提升攻击力为x的技能呢?其实这是不可能的,因为我们是对提升的攻击力进行二分,所以所得结果一定是最优的,假如我们二分得到的结果是x,那么可以满足大于x的技能全部被使用光,而且大于等于x的技能一定会有剩余,这是我们的二分性质决定的,所以直接对最低提升攻击力点数进行二分即可。细节见代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll a[N],b[N];
int n,m;
bool check(ll x)
{
	ll cnt=0;
	x++;//至少要等于x+1的攻击力才能使用该技能
	for(int i=1;i<=n;i++)
	{
		if(a[i]m) return false;//剪枝 
	}
	return true;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&a[i],&b[i]);
	ll l=0,r=1e6;
	while(l>1;//本次增加的攻击力是要大于mid的 
		if(check(mid))
			r=mid;
		else l=mid+1;
	}
	ll ans=0;
	int cnt=0;//使用增加攻击力大于l的技能次数 
	for(int i=1;i<=n;i++)
	{
		if(a[i]<=l) continue;
		ll times=(a[i]-(l+1))/b[i]+1;
		cnt+=times;
		ans+=(a[i]+a[i]-(times-1)*b[i])*times/2;
	} 
	ans+=(m-cnt)*l;
	printf("%lld\n",ans);
	return 0;
} 

你可能感兴趣的:(蓝桥杯备考,二分,算法,蓝桥杯)