P2672 [NOIP 2015 普及组] 推销员 解题笔记
题意
阿明要给胡同里的 \(n\) 个住户推销,第 \(i\) 个住户距离为 \(s_i\),推销完会产生 \(a_i\) 的疲劳值,每走一个距离会产生 \(1\) 点疲劳值。推销完后需原路返回,分别求不走无用路时推销 \(x\) 个住户的最大疲劳值(\(x\) 为 \(1\) 到 \(n\) 的任意值)。
思路
考虑贪心。
如果没有距离,那么就是贪疲劳值,直接取前 \(x\) 个疲劳值最大的就好了。
加上距离后有两种情况:
- 直接取前 \(x\) 个疲劳值最大的。
- 舍弃疲劳值最小的,选择距离最远的。
代码实现:
-
先将住户按 \(a_i\) 降序排序。
-
计算 \(sum\) 数组为 \(a_i\) 的前缀和。\(s\) 为 \(s_i\) 的最大值。\(maxx\) 为 \(a_i + 2 \times s_i\) 的后缀和。
-
循环 \(1\) 到 \(n\) 计算答案。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, sum[N], s[N], maxx[N], mx;
struct node
{
int a, s;
}a[N];
bool cmp(node a, node b)
{
return a.a > b.a;
}
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i].s;
for(int i = 1; i <= n; i ++) cin >> a[i].a;
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i ++)
{
sum[i] = sum[i - 1] + a[i].a;
s[i] = max(s[i - 1], a[i].s);
}
for(int i = n; i >= 1; i --)
{
maxx[i] = max(maxx[i + 1], a[i].a + 2 * a[i].s);
}
for(int i = 1; i <= n; i ++)
{
mx = max(mx, a[i].s);
int ans = max(sum[i] + mx * 2, sum[i - 1] + maxx[i]);
cout << ans << endl;
}
}

浙公网安备 33010602011771号