P2672 推销员

Posted this-is-m

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2672 推销员相关的知识,希望对你有一定的参考价值。

说在题解之前的话

今天这个题,已经有两位大佬讲过了 ,我作为一个蒟蒻只是作一作补充,让自己理解的更深一点

这是链接QWQ

技术图片

这个题看到标签是技术图片

看完之后就明白了,这题要凉,反正头铁呗,我们就用贪心来做这个题

认真分析之后,我们什么思路也没有,一开始考虑对于a来贪心,将其降序排列,然后取前x个算个总和就行了。因为这个题水的出奇,所以AC了,但是后来神仙发现这个是错误的,举一个简单的例子,如果有一个点a特别小但是距离特别远,你如果不选这个点,那么答案很有可能是错的。因为这个贪心实在是太水了,我也不多讲。

考虑正确解法

基于a降序排列本身没有问题,但是我们的用法不对,如果我们只是按照a来算的话,就会出现上面那种错误,对于每一个x,我们总共有两种选择

1、选择前x个最大的作为答案

2、选择前x-1个数,在第x个数选择s[i]*2+a[i],为什么这么考虑呢?

因为对于路程的贡献,是只有最长路径的点才有的。

我们是这么走路

技术图片

而不是

技术图片

虽然很丑,但是能够清晰的说明我们只来回一次,所以想要体力值消耗最大,一定是先选x-1个a最大的,然后选s[i]*2+a[i]最大的那个点(我怎么感觉我在废话)

总之贪心策略就是这样,我们只需要预处理出sum[i]维护前缀和,f[i]表示i-n中s[i]*2+a[i]最大的点,max[i]表示i之前最大的点就行啦

这是代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std; 
inline int read()
    int res = 0;
    char last =  , ch = getchar();
    while(ch < 0 || ch > 9)    last = ch, ch = getchar();
    while(ch >= 0 && ch <= 9) res = (res << 1) + (res << 3) + (ch ^ 48), ch = getchar();
    if (last == -)    res = -res;
    return res;

struct qwq
    int sum, value, s, f, Max;
p[1000010];//people
bool cmp (qwq a,qwq b)
    return a.value > b.value;

int main()
    int n;
    n = read();
    for (int i = 1; i <= n; ++i)
        p[i].s = read();
    for (int i = 1; i <= n; ++i)
        p[i].value = read();
    sort (p + 1, p + n + 1, cmp);
    for (int i = 1; i <= n; ++i)
        p[i].sum = p[i-1].sum + p[i].value;
        p[i].Max = max(p[i - 1].Max, p[i].s);
    
    for (int i = n; i >= 1; --i)
        p[i].f = max(p[i + 1].f, 2 * p[i].s + p[i].value);
    for (int i = 1; i <= n; ++i)
        printf("%d\\n", max(p[i].sum + 2 * p[i].Max, p[i-1].sum + p[i].f));
    return 0;

 

但是莫名其妙的RE加TLE了,后来发现改成数组就行,懒得改了就这样吧

以上是关于P2672 推销员的主要内容,如果未能解决你的问题,请参考以下文章

11.13刷题列表

有多个推销员的旅行推销员,每个推销员的城市数量有限制?

[NOIP2015]推销员

图书-财经:《世界上最伟大的推销员》

推销员(优先队列+贪心)

noip2015普及组 推销员