思路是贪心地选择单价低的物品。二分物品单价上限,check 判断每种物品选择最多的数量,使得单价不超过上限,总花费是否合法。
最后再判断每种物品有没有可能数量再多一个,使得总花费仍然合法。
楼主可能晚一点再上线,先下线了,见谅。
提前拜谢大佬orz
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace gigantic {
constexpr int N=2e5+7;
int n;
ll m;
int p[N];
ll l,r;
ll check(ll lim) {
ll sum=0;
ll cnt=0;
int it=1;
while(sum<=m && it<=n) {
ll s=(lim/p[it]-1)/2+1;
cnt+=s;
sum+=s*s*p[it];
++it;
// if(lim==44) pf("cnt = %lld\n",cnt);
}
if(sum<=m) return cnt;
return -1;
}
ll x;
ll ans;
ll c[N];
void main() {
sf("%d%lld",&n,&m);
rep(i,1,n) sf("%d",&p[i]);
l=0,r=m;
while(l<r) {
ll mid=(l+r+1)>>1;
// pf("mid = %lld\n",mid);
x=check(mid);
if(x!=-1) l=mid, ans=x;
else r=mid-1;
}
ans=0;
ll sum=0;
rep(it,1,n) {
ll s=(l/p[it]-1)/2+1;
ans+=s;
c[it]=s;
sum+=s*s*p[it];
}
vector<int> vec;
rep(i,1,n) {
vec.push_back((2ll*c[i]+1)*p[i]);
}
sort(vec.begin(),vec.end());
for(ll cost : vec) {
if(cost+sum<=m) ++ans,sum+=cost;
else break;
}
// pf("l = %lld\n",l);
pf("%lld\n",ans);
}
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
gigantic :: main();
}