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了,后来发现改成数组就行,懒得改了就这样吧

posted @ 2019-07-03 19:24  Emiya_Shirou  阅读(235)  评论(0编辑  收藏  举报