P2672 推销员
说在题解之前的话
今天这个题,已经有两位大佬讲过了 ,我作为一个蒟蒻只是作一作补充,让自己理解的更深一点
这个题看到标签是
看完之后就明白了,这题要凉,反正头铁呗,我们就用贪心来做这个题
认真分析之后,我们什么思路也没有,一开始考虑对于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了,后来发现改成数组就行,懒得改了就这样吧