因为 \(n \leq 1e9\) ,所以 \(dp\) 肯定是行不通的,那就基本上只能考虑贪心。这个题刚开始还是很容易想到用贪心的方法,能想到的策略也有很多,我记得我听过一句话
刚开始可能会想,\(a_i\) 最大的会不会一定要拿,或者 \(b_i\) 最大的要不要优先考虑
------
100 2
2 1
1 100
------
2 3
8 1
7 1
6 2
------
通过这两组样例就知道之前想的两个贪心策略都是错误的。
经过思考后就会发现,可能的情况是在太多,如果直接贪心完全无法保证结果最大。
那么这时候就要考虑先枚举一些东西。
我们先想想解的形式。
这其实就是全部可能的解了,第一种情况很好写,现在直接想第二种情况。
虽然这个题是贪心,但不代表不能枚举,所以我们如果枚举第 \(i\) 种花选了多个,按照上述规则找到一个可行解,只要找到所有的取最大值即可。
那么现在选了第 \(i\) 种,该如何快速得到比 \(b_i\) 大的 \(a_j\) 的和呢?
我们将 \(a\) 先排序,同时也将 \(b\) 排序 ( 分开存且均从大到小 )
由于 \(b_i \ge b_{i+1}\) 所以所有比 \(b_{i+1}\) 大的 \(a_j\) 一定包含了所有比 \(b_i\) 大的,由于 \(a\) 也是有序的,那么只需要将在 \(b_i\) 与 \(b_{i+1}\) 范围内的 \(a\) 加进和即可 ( 记得统计 \(a_i\) 是否被包括进和里,也可通过 \(a_i\) 和 \(b_i\) 的大小关系判断,如果 \(a_i \ge b_i\) 那么被算进和了) ,还需要注意 只能选 n 个数!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Maxn = 1e5+10;
const int Inf = 0x7f7f7f7f;
const int Mod = 1e9+7;
struct Flower1{
int a,pos;
}f1[Maxn];
struct Flower2{
int b,pos,a;
}f2[Maxn];
bool cmpa(Flower1 a,Flower1 b){
return a.a > b.a;
}
bool cmpb(Flower2 a,Flower2 b){
return a.b > b.b;
}
bool vis[Maxn];
int main(){
int T;
scanf("%d",&T);
while( T-- )
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d %d",&f1[i].a,&f2[i].b), f1[i].pos = f2[i].pos = i, f2[i].a = f1[i].a;
// 排序
sort(f1+1,f1+1+m,cmpa);
sort(f2+1,f2+1+m,cmpb);
ll ans = 0,Sum = 0;
// 处理第一个解的情况
if( n <= m )
for(int i=1;i<=n;i++) ans += f1[i].a;
for(int j=1,i=1;j<=m;j++)
{
// 将比 f2[j].b 大的 a 算进和
while( i <= n && i <= m && f1[i].a >= f2[j].b )
{
Sum += f1[i].a;
vis[f1[i].pos] = true;
i++;
}
// 只能选 n 个
if( i == n+1 ) break;
if( vis[f2[j].pos] ) // f2[j].a >= f2[j].b
ans = max(ans,Sum + 1ll*f2[j].b*(n-i+1));
else
ans = max(ans,Sum + 1ll*f2[j].a + 1ll*f2[j].b*(n-i));
}
printf("%lld\n",ans);
for(int i=1;i<=m;i++) vis[i] = false;
}
return 0;
}
Codeforces Round #657 (Div. 2).C
原文:https://www.cnblogs.com/HexQwQ/p/13341913.html