CSP历年复赛题-P2672 [NOIP2015 普及组] 推销员

原题链接:https://www.luogu.com.cn/problem/P2672

题意解读:N家住户,每家住户与出入口距离是Si米,推销员每走1米疲劳值+1,向第i家住户推销疲劳值+Ai,推销员推销完原路返回出口,计算在向不同数量X的住户推销时,能达到的最大疲劳值。

解题思路:

本题是一种贪心选择问题,需要思考出可能的最优解,并取最大值。

最直观的思路,要计算给X个住户推销的最大疲劳值,取前X个疲劳值最大的住户即可,这样“总的疲劳值=x个最大疲劳值之和+前x住户最远距离*2”

但还有一种可能,如果在前X个最大疲劳值住户里,去掉一个疲劳值最小的,换一家在X以后的住户里“距离*2+疲劳值”最大的,这样总的疲劳值是可能更大的,这时“总的疲劳值=(X之后距离*2+疲劳值的最大值) + 前X-1个最大疲劳值之和”

对以上两种情况计算的总疲劳值求max即可

为了加速“前x个最大疲劳值之和”,“前x个住户最远距离”,“x之后的距离*2+疲劳值的最大值”的计算,可以定义三个数组并提前预处理:

p[i]:前i个最大的疲劳值Ai之和

s[i]:前i个最大的疲劳值住户中最远的距离

w[i]:第i个之后的住户“距离*2+疲劳值”最大值

预处理以上数组之后,x从1枚举到n,每次计算两种疲劳值并取max:

max(p[x] + s[x] * 2, w[x] + p[x-1])

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;

struct node
{
    int s, a;
};
node q[N];
int n;
int p[N]; //p[i]:前i个最大的疲劳值Ai之和
int s[N]; //s[i]:前i个最大的疲劳值住户中最远的距离
int w[N]; //w[i]:第i个之后的住户“距离*2+疲劳值”最大值

bool cmp(node q1, node q2)
{
    return q1.a > q2.a; //按疲劳值从大到小排序
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> q[i].s;
    for(int i = 1; i <= n; i++) cin >> q[i].a;

    sort(q + 1, q + n + 1, cmp);

    for(int i = 1; i <= n; i++) p[i] = p[i-1] + q[i].a;
    for(int i = 1; i <= n; i++) s[i] = max(s[i-1], q[i].s);
    for(int i = n; i >= 0; i--) w[i] = max(w[i+1], q[i].s * 2 + q[i].a);

    for(int x = 1; x <= n; x++) cout << max(p[x] + s[x] * 2, w[x] + p[x-1]) << endl;
}

 

posted @ 2024-06-06 10:58  五月江城  阅读(40)  评论(0编辑  收藏  举报