\(\sf D-PriceFixed\)
题目
简要题意
在一个折扣店有 \(n\) 种商品,每种商品的价格都是 \(2\)。对于商品 \(i\) 你需要买 \(a_i\) 个,而如果在买商品 \(i\) 之前你购买的商品数量(指所有种类的商品数量)大于等于 \(b_i\),你就可以半价购买商品 \(i\)。
请合理安排商品购买顺序使得完成购买任务所花费的钱最少。
数据范围与提示
\(n\le 1e5,\ 1\le a_i,b_i\le 10^{14}\)。
解法
#1. \(\text{Two Pointers}\)
贪心地想,在当前 \(b_i\) 最小的商品不能半价时买 \(b_i\) 最大的商品一定不会更劣。
所以可以直接将商品按 \(b_i\) 排序,用两个指针 \(l,r\) 往中间遍历。我们用牺牲 \(r\) 换取 \(l\) 的半价。
#2. \(\text{Binary Search}\)
我们还是将商品按 \(b_i\) 排序。那么任务就是最小化全价商品数。
二分全价商品数 \(\rm mid\)。检验是否合法就是按排序顺序遍历商品,购买能够买到的所有半价商品数记其为 \(w\),如果满足 \(\text{mid}+w\ge \sum a_i\) 就合法。
时间复杂度 \(\mathcal O(n\log 10^{14})\)。
代码
#1. \(\text{Two Pointers}\)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>‘9‘||s<‘0‘) if(s==‘-‘) f=-1;
while(s>=‘0‘&&s<=‘9‘) x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar(‘-‘),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
typedef long long ll;
typedef pair <ll,ll> Pair;
const int maxn=1e5+5;
int n;
Pair s[maxn];
int main() {
n=read(9);
rep(i,1,n) s[i].second=read(9ll),s[i].first=read(9ll);
sort(s+1,s+n+1);
ll ans=0,sum=0; int l=1,r=n;
while(l<r) {
if(sum<s[l].first) {
if(s[r].second>s[l].first-sum) {
s[r].second-=s[l].first-sum;
ans+=(s[l].first-sum)*2,sum=s[l].first;
}
else {
sum+=s[r].second;
ans+=s[r].second*2; s[r].second=0,--r;
}
if(sum>=s[l].first) {
sum+=s[l].second,ans+=s[l].second,++l;
}
}
else sum+=s[l].second,ans+=s[l].second,++l;
}
if(l==r) {
if(sum>=s[l].first) ans+=s[l].second;
else {
if(s[l].second>s[l].first-sum)
ans+=(s[l].first-sum)*2+s[l].second-s[l].first+sum;
else ans+=s[l].second*2;
}
}
print(ans,‘\n‘);
return 0;
}
#2. \(\text{Binary Search}\)
#include <bits/stdc++.h>
using namespace std;
bool cmp(pair<long long, long long> &x, pair<long long, long long> &y) {
return x.second < y.second;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n; cin >> n;
vector<pair<long long, long long>> in(n);
for(int i = 0; i < n; i++) {
cin >> in[i].first >> in[i].second;
}
sort(in.begin(), in.end(), cmp);
long long lo = 0LL, hi = 1e15, tot = 0LL;
for(int i = 0; i < n; i++) {
tot += in[i].first;
}
for(int j = 0; j < 60; j++) {
long long tst = (lo + hi) / 2;
long long soFar = tst;
for(int i = 0; i < n; i++) {
if(soFar >= in[i].second)
soFar += in[i].first;
}
if(soFar >= tot) {
hi = tst;
}
else lo = tst + 1;
}
cout << tot + lo << "\n";
}