传送门
题意:
市场上有 \(a[i]\) 种商品,每种商品的价格都是\(2\)。现在你需要买这种商品 \(a [ i ]\) 件。但是对于第\(i\)种商品有一个属性\(bi\),意味着如果你已经买了\(bi\)件商品(不一定是这一种商品),那么此商品打折,价格会降到\(1\)。
思路:
双指针 + 贪心,对于\(bi\)大的商品,在都没达到要求之前肯定是去最不可能达到的是最优的,如果达到了,肯定要把达到的都取完,直到不达到,然后重复此步骤最终的结果就是答案,写这个代码有点巧妙,对于这个过程有三种状态,当前取的量大于\(a[r].second\),那么直接全取,如\(a[l].first\)全加了之后还是不行,那么直接全取\(a[l].first\), 如果\(count + a[l].first >= a[r].second\), 那么先把l里面的那部分2的先取,然后在把问题转换为上面的状态
总结:
双指针思想,贪心策略的完备性,代码的总结性
点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;
typedef long long ll;
ll n;
bool comp(pair<ll, ll> x, pair<ll, ll> y)
{
return x.second > y.second;
}
int main()
{
IOS; cin.tie(0), cout.tie(0);
cin >> n;
vector<pair<ll, ll>> a(n); //first代表数量,second至少要几个就可以半价了
ll sum = 0;
for (int i = 0; i < n; ++i)
cin >> a[i].first >> a[i].second, sum += a[i].first;
sort(a.begin(), a.end(), comp);
ll l = 0, r = n - 1, count = 0, ans = 0;
while (count != sum)
{
if (count >= a[r].second) //当前的数量已经可以使a[r]为空
count += a[r].first, ans += a[r].first, --r;
else if (count + a[l].first >= a[r].second)
a[l].first -= a[r].second - count, ans += 2 * (a[r].second - count), count = a[r].second;
else //全取都不行,直接全取
count += a[l].first, ans += 2 * a[l].first, ++l;
}
cout << ans << endl;
return 0;
}
/*
8
1 8
1 6
1 5
1 3
1 3
1 8
1 7
1 3
*/