卧薪尝胆,厚积薄发。
提高A组模拟 陪审团
Date: Fri Aug 17 17:07:00 CST 2018 In Category: NoCategory

Description:

有 $n$ 个人,每个人有两个属性 $x_i$ 和 $y_i$ ,现在甲从这 $n$ 个人中挑 $s$ 个人,乙从这 $s$ 个人中挑 $t$ 个人,甲想让这 $t$ 个人 $x$ 属性之和最大,同时 $y$ 之和最小,乙相反,问怎样选能使 $x$ 属性之和最大,在此基础上 $s-t$ 个人 $y$ 属性最大,在此基础上 $s$ 的 $x$ 最大,输出 $x$ 和 $y$ 属性之和。
$1\le n \le 100000$

Solution:

显然按 $y_i$ 排序的后 $s-t$ 个一定不会被选到最终的答案里,而其他的都有可能,于是就按 $y_i$ 从小到大排序, $y$ 相同时按 $x$ 从大到小排序,去掉最后的 $s-t$ 个,在去掉后的数组中选出 $x$ 最大时 $y$ 最大的 $t$ 个作为最终的答案,之所以选 $y$ 最大是因为要让 $s-t$ 那些人的 $y$ 最大,这些 $y$ 一定都小于 $t$ 的 $y$ ,问题就变成了构造一种方案使得这 $t$ 个能被取为最终的答案,发现只有 $y_i\le y_k$ 的人可能被乙排掉,于是就再把剩下的按 $y$ 排序,选 $y_i\le y_k$ 中 $y$ 最大的就行了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,s,t;
#define MAXN 100010
struct peo{int x,y,tag;}p[MAXN];
bool cmp_maxy_maxx(peo a,peo b){return (a.y == b.y ? a.x > b.x : a.y > b.y);}
bool cmp_miny_maxx(peo a,peo b){return (a.y == b.y ? a.x > b.x : a.y < b.y);}
bool cmp_minx_maxy(peo a,peo b){return (a.x == b.x ? a.y > b.y : a.x < b.x);}
bool cmp_miny_minx(peo a,peo b){return (a.y == b.y ? a.x < b.x : a.y < b.y);}
bool cmp_minx_miny(peo a,peo b){return (a.x == b.x ? a.y < b.y : a.x < b.x);}
int main()
{
scanf("%d%d%d",&n,&s,&t);
for(int i = 1;i <= n;++i)scanf("%d%d",&p[i].x,&p[i].y);
sort(p + 1,p + 1 + n,cmp_miny_maxx);
sort(p + 1 + s - t,p + 1 + n,cmp_minx_miny);
long long sumx = 0,sumy = 0;
for(int i = 1;i <= t;++i)
{
sumx += p[n - i + 1].x;
sumy += p[n - i + 1].y;
p[n - i + 1].tag = 1;
}
sort(p + 1,p + 1 + n,cmp_miny_minx);
int pos;
for(pos = 1;pos <= n && p[pos + 1].tag != 1;++pos);
for(int i = pos;i >= pos - (s - t) + 1;--i)
{
sumx += p[i].x;
sumy += p[i].y;
}
cout << sumx << " " << sumy << endl;
return 0;
}
In tag: 算法-贪心
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡