有些人执着|

园龄:粉丝:关注:

题解:AT_abc389_e [ABC389E] Square Price

前言

E 比 F 困难,怎么会是呢?

思路分析

首先考虑一种经典做法:将问题转化为物品体积为 pi,3pi,5pi,7pi 的 01 背包问题。因为物品价值都为 1,所以可以贪心地选择体积前 k 小的物品。

然后问题转化到这一步就自然了,考虑二分出我们选与不选的物品体积的临界值,小于等于这个值的物品都选上。

已知临界值 mid,对于每一个 pi,我们选择的物品数量 k 应该满足:

(2k1)pimid

放缩一下:

kmidpi+12

这里有一个细节:在选完小于等于临界值的物品后,如果背包容量还有剩余,会考虑选择大于临界值的物品,特判一下即可。

总体复杂度 O(nlogm)

代码实现

不知道在 check 时会不会炸 long long,所以开了 __int128。

#include<bits/stdc++.h>
using namespace std;
long long ans,p[200005],sum,m,n,maxn;
bool check(long long ans){
	__int128 sum=0;
	for(int i=1;i<=n;i++){
		__int128 num=((ans/p[i]+1))/2;
		sum+=num*num*p[i];
		if(sum>m) return false;
	}
	return true;
}
long long find(long long l,long long r){
	if(l==r) return l;
	long long mid=(l+r+1)>>1;
	if(check(mid)) return find(mid,r);
	else return find(l,mid-1);
}
int main(){
	//freopen("in.in","r",stdin);
	//freopen("out.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(long long i=1;i<=n;i++){
		cin>>p[i];
	}
	ans=find(0,m);
	for(long long i=1;i<=n;i++){
		__int128 num=(ans/p[i]+1)/2;
		sum+=num;
		m-=num*num*p[i];
		maxn=max((__int128)maxn,(2*num+1)*p[i]);
	}
	sum+=m/maxn;
	cout<<sum;
	return 0;
}

本文作者:Kenma

本文链接:https://www.cnblogs.com/Kenma/p/18689777

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Kenma  阅读(46)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起