[I. Quartz Collection](Problem - I - Codeforces)
题意 :
- 商店里面有n个种类宝石,分别给出第一次购买和第二次购买的价格,只有购买完第一次后才能用第二次购买的价格,两人都想用最少的成本购买宝石
- 购买的顺序是 : 爱丽丝先买一块石英,然后鲍勃和爱丽丝轮流买两块,直到只剩下一块。还没有收集到所有类型的石英的人买了最后一块
- 然后m次修改操作,修改某一种类宝石第一次购买和第二次购买的价格,每轮修改后输出爱丽丝的最小花费
分析 :
STEP 1 .贪心
我们先用贪心去想,假设我们都是选择第一次购买的价格,设总和是sum1,那么考虑i物品选择第二次购买就有收益为 A[ i ] - B[ i ] (第一次价格减第二次价格),那么我们尽可能令 A[i] - B[i] 最小
-初步思路: 所以把A[ i ] - B[ i ]排序 ,根据购买的顺序,小于0的数是我连着拿两个,他拿两个(尽量拿)而大于0的数,是我拿一个数,回去拿一个Bob买过的(尽量不拿)
STEP2. 值域线段树求解:
什么是值域线段树:
线段树里面存区间和在区间内的数的个数
那么对于每次修改,我们拿的位置是确定的,我们用值域线段树维护sum[4],分别表示从i号位相隔4个位置的和(例如 1 2 3 4 5 6 7 3 2 ,sum[0] = 1 + 5 + 2),那么对于Bob ,小于0区间的sum[2]+sum[3] 就是他取的值,大于0的部分需要根据小于0的奇偶性来判别
关键代码如下:
ll ask(ll ans){
Tree a1 = seg.ask(1,-100000,0);
Tree a2 = seg.ask(1,1,100000);
ans -= a1.sum[1] + a1.sum[2];(负数间隔两个取最优)
if(a1.sz%2==0){
ans -= a2.sum[1] + a2.sum[3]; (正数间隔1个取最优)
}
else ans -= a2.sum[0] + a2.sum[2];
return ans;
}
AC 代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+7;
typedef long long ll;
int A[N],B[N];
struct Tree{
int l=0,r,sum[4],sz;
};
void add_tr(Tree & tr,Tree & tr1){
int siz = tr.s

文章讨论了一道Codeforces的题目,涉及宝石购买的策略。使用贪心算法,首先按第一次购买价格与第二次购买价格之差排序,然后利用值域线段树维护每种宝石的购买情况。在每次价格修改后,通过线段树计算爱丽丝的最小花费。
最低0.47元/天 解锁文章
253

被折叠的 条评论
为什么被折叠?



