【题解】Luogu P14635 [NOIP2025] 糖果店 / candy
思路
首先不难想到,如果要取一个糖果两次,为了使花费最小,我们一定要取 \(x_i+y_i\) 最小的糖果。
然后是取一次的糖果,显然要取 \(x_i\) 最小的前若干个,所以先对 \(x_i\) 排序。
接着就有两种处理思路:
第一种,可以观察到花费随糖果数量增加而增加,因此我们可以二分糖果数量 \(k\),然后枚举 \(k\) 个糖果中,有多少是取两次得到的,有多少是取一次得到的。根据上面的规则,我们很容易计算出总花费。时间复杂度 \(O(n\log m)\)。
第二种,注意到取一次的糖果数量只能是 \(1\sim n\),所以我们直接枚举取多少个一次。一种实现是先贪心,尽可能多地取两次,然后再从小到大去取一次的糖果,钱不够就反悔删掉一组两次(比一组还大的一次一定不优,不用管),最终答案是其中产生的最大值。也可以直接枚举取多少一次,计算出对应的取两次数目。处理时间复杂度 \(O(n)\),总 \(O(n\log n)\)。
两种做法都足以通过,但显然第二种更优。
实现
为第二种写法。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
struct Node{
int x,y;
}a[N],b[N];
int n,pos;
int m,ans,mina=1e18;
bool cmp(Node p,Node q){
return p.x<q.x;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
b[i]=a[i];
if(a[i].x+a[i].y<mina){
mina=a[i].x+a[i].y;
pos=i;
}
}
ans+=(m/mina)*2;
m%=mina;
int t=ans;
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++){
if(m<b[i].x){
if(b[i].x>mina) break;
t-=2;
m+=mina;
};
t++;
m-=b[i].x;
ans=max(ans,t);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号