传送门:题目
题意:
一个人,想要购买两件商品,有两种货币,每件商品能且之能用一种货币购买,每件商品都有一个权重,我们想让购买的商品权重和最大,要求输出最大的权重和,如果没办法购买两件商品,输出0
题解:
第一开始看到数据范围 105 10 5 ,想到这道题得用线段树了。然后突然想到先按权重从大到小排,然后找到能够购买的权重最大的商品,找到后直接break就行了(贪心),这样复杂度到不了 n2 n 2 ,然后就暴力写了一下,果然AC了。
线段树写法:
后来又用线段树RMQ写了一下,也很简单的,我直接套了个模板上去。
然后注意一下,先Query然后Update,这样可以避免Query到自己。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100010;
struct Node {
int beauty, cost;
bool operator<(const Node& rhs)const {
return beauty > rhs.beauty;
}
} nodec[maxn], noded[maxn];
int main(void) {
char ch;
int i, j, n, C, D, nc = 0, nd = 0, t1, t2, ans = 0,indexc=0,indexd=0;
//C D是拥有的资产,nc和nd是类别为c或d商品的总数量,t1t2是临时变量,indexc和indexd是记录能够购买的魅力值最大商品的索引值
cin>>n>>C>>D;
for (int i = 0; i < n; i++) {
cin>>t1>>t2>>ch;
if (ch == 'C')
nodec[nc].beauty = t1, nodec[nc++].cost = t2;//事实上,这里用vector更简明,但是怕TLE,就没敢用
else if (ch == 'D')
noded[nd].beauty = t1, noded[nd++].cost = t2;
}
sort(nodec, nodec + nc),sort(noded, noded + nd);//按美丽值从大到小排序
for (i = 0; i < nc; i++)//下面两个for以贪心的策略找到美丽值最大的可购买的商品
if (nodec[i].cost <= C) {
indexc=i,ans += nodec[i].beauty;
break;
}
for ( j = 0; j < nd; j++)
if (noded[j].cost <= D) {
indexd=j,ans += noded[j].beauty;
break;
}
if (i == nc || j == nd)//如果只有一件可购买,则把答案重置为0,因为题目要求能且只能购买两件。
ans = 0;
for (i = indexc; i < nc; i++)//只用C买两件,看看能不能达到最大
for (j = i + 1; j < nc; j++)
if (nodec[i].cost + nodec[j].cost <= C){
ans = max(ans, nodec[i].beauty + nodec[j].beauty);
break;//因为我们已经排好序了,所以只要满足条件,我们就可以退出
}
for (i = indexd; i < nd; i++)//只用D买两件,看看能不能达到最大
for (j = i + 1; j < nd; j++)
if (noded[i].cost + noded[j].cost <= D){
ans = max(ans, noded[i].beauty + noded[j].beauty);
break;//因为我们已经排好序了,所以只要满足条件,我们就可以退出
}
cout << ans << endl;
return 0;
}
AC代码(线段树):
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
pair<int, int> pii; //first->beauty second->cost
vector<pair<int, int> > c, d;
/******************线段树模板**********************/
int SegTree[maxn << 2];
void BuildTree(int l, int r, int rt) {//建树,lr是总区间,rt是根结点一般为1
if (l == r) {
SegTree[rt] = 0; //初始化叶节点
return ;
}
int m = (l + r) >> 1;
BuildTree(l, m, rt << 1);
BuildTree(m + 1, r, rt << 1 | 1);
SegTree[rt] = SegTree[rt << 1] + SegTree[rt << 1 | 1];
}
int Query(int L, int R, int l, int r, int rt) {//区间查询,LR是查询区间,lr是总区间,rt是根结点一般为1
if (l >= L && r <= R)
return SegTree[rt];
int m = (l + r) >> 1;
int ans1 = 0,ans2=0;
if (L <= m)
ans1 = Query(L, R, l, m, rt << 1);
if (R > m)
ans2 = Query(L, R, m + 1, r, rt << 1 | 1);
return max(ans1,ans2);
}
void Update(int point, int value, int l, int r, int rt) {//单点更新,把point点的值改为value,lr是总区间,rt是根结点一般为1
if (l == r) {
SegTree[rt] = max(value,SegTree[rt]);
return;
}
int m = (l + r) >> 1;
if (point <= m)
Update(point, value, l, m, rt << 1);
else
Update(point, value, m + 1, r, rt << 1 | 1);
SegTree[rt] = max(SegTree[rt << 1] , SegTree[rt << 1 | 1]);
}
/******************线段树模板**********************/
int main(void) {
char ch;
int n, C, D, t1, t2, max_cost = 0, ans = 0;
cin >> n >> C >> D;
for (int i = 0; i < n; i++) {
cin >> t1 >> t2 >> ch;
pii = make_pair(t1, t2);
ch == 'C' ? c.push_back(pii) : d.push_back(pii);
max_cost = max(t2, max_cost);
}
max_cost = max(max_cost, max(C, D));
t1 = t2 = 0;//C买一件D买一件
for (int i = 0; i < (int)c.size(); i++)
if (C >= c[i].second)
t1 = max(t1, c[i].first);
for (int i = 0; i < (int)d.size(); i++)
if (D >= d[i].second)
t2 = max(t2, d[i].first);
if ((t1 & t2) != 0) //t1和t2均不为0
ans = t1 + t2;
BuildTree(0, max_cost, 1);//买C两件
for (auto x : c) {
t1 = 0;
if (C > x.second)
t1 = Query(1, C - x.second, 0, max_cost, 1);
Update(x.second, x.first, 0, max_cost, 1);
if (t1 != 0)
ans = max(ans, x.first + t1);
}
BuildTree(0, max_cost, 1);//买D两件
for (auto x : d) {
t1 = 0;
if (D > x.second)
t1 = Query(1, D - x.second, 0, max_cost, 1);
Update(x.second, x.first, 0, max_cost, 1);
if (t1 != 0)
ans = max(ans, x.first + t1);
}
cout << ans << endl;
return 0;
}

通过贪心算法和线段树RMQ解决购物权重最大化问题,利用两种货币购买商品以获得最大权重和。
140

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



