这道题真是让我深刻地陷入了对我智商的怀疑。。。比赛想了50min,结果最后评出来难度是

过分了啊。。。
题目大意

解题思路
贪心。
可以看出,每个数aia_iai对答案的贡献是±ai\pm a_i±ai。(因为它要么被减,要么被加。)那么我们尽量让每个数的贡献为其绝对值。又注意到a1a_1a1的贡献永远是a1a_1a1本身(因为没有哪个数能减它)。那么,最优解就是a1+∑i=2n∣ai∣a_1+\sum \limits_{i=2}^n|a_i|a1+i=2∑n∣ai∣。
下面证明最优解一定可以构造出来。考虑从右往左合并,对于当前数aia_iai和合并其右边的数已经得到的数±∑j=i+1n∣aj∣\pm \sum \limits_{j=i+1}^n|a_j|±j=i+1∑n∣aj∣,若aia_iai和±∑j=i+1n∣aj∣\pm \sum \limits_{j=i+1}^n|a_j|±j=i+1∑n∣aj∣同号,则执行x+yx+yx+y,否则执行x−yx-yx−y,使得后iii个数得到的和为±∑j=in∣aj∣\pm \sum \limits_{j=i}^n|a_j|±j=i∑n∣aj∣。最终答案就是a1+∑i=2n∣ai∣a_1+\sum \limits_{i=2}^n|a_i|a1+i=2∑n∣ai∣。
时间复杂度:O(n)O(n)O(n)。
奉上高清无码Code:
#include <cstdio>
#include <cstdlib>
#include <cctype>
using namespace std;
typedef long long ll;
ll n;
inline ll read() // 快速读入
{
ll ret = 0;
char sgn = 0;
char c;
while(!isdigit(c = getchar())) if(c == '-') sgn = 1;
ret = c ^ 48;
while(isdigit(c = getchar())) ret = (ret << 1) + (ret << 3) + (c ^ 48);
return sgn ? -ret : ret;
}
int main()
{
n = read();
ll ans = read(); // ans = a[1]
while(--n) ans += llabs(read());
// ans += |a[2]| + |a[3]| + ... + |a[n]|
printf("%lld\n", ans);
return 0;
}
如果还不理解的话,举个栗子:
5
-1 2 -3 4 -5
4−(−5)→(−1,2,−3,9)4-(-5)\to(-1,2,-3,9)4−(−5)→(−1,2,−3,9)
−3−9→(−1,2,−12)-3-9\to(-1,2,-12)−3−9→(−1,2,−12)
2−(−12)→−1,142-(-12)\to-1,142−(−12)→−1,14
−1+14→13-1+14\to13−1+14→13
答案就是13=−1+∣2∣+∣−3∣+∣4∣+∣−5∣=a1+∑i=2n∣ai∣13=-1+|2|+|-3|+|4|+|-5|=a_1+\sum \limits_{i=2}^n|a_i|13=−1+∣2∣+∣−3∣+∣4∣+∣−5∣=a1+i=2∑n∣ai∣。
一题贪心算法解析

本文解析了一道关于贪心算法的题目,通过分析每个数对答案的贡献,提出了解决方案并给出了代码实现。
378

被折叠的 条评论
为什么被折叠?



