题目
思路
因为最后只剩一个小朋友没入选,所以我们自然想到要找到那个落单的小朋友。
先简单举一个例子:如果有5个小朋友,niceness为ai.
- 如果不选一号小朋友,剩下4个的贡献都是-ai;
- 如果不选二号小朋友,其余4个的贡献为:+a1,-a3,-a4,-a5;
- 如果不选三号小朋友,其余4个的贡献为:+a1,+a2/-a2,-a4,-a5;
- 如果不选四号小朋友,其余4个的贡献为:+a1,+a2/-a2,+a3/-a3,-a5;
- 如果不选五号小朋友,其余4个的贡献为:+a1,+a2/-a2,+a3/-a3,+a4/-a4;
不难发现,第一个小朋友的贡献始终为+a1,不选的小朋友之前的小朋友(除一号小朋友)的贡献+-都可取到,所以要求最大值,我们就取|ai|。不选的小朋友之后的小朋友的贡献只能说-ai。
所以我们可以预处理|ai|的前缀和(不含a1)和-ai的后缀和。
时间复杂度:O(n)
AC code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
void solve() {
int n;
cin >> n;
vector<int>a(n);
for (int i = 0;i < n;++i)cin >> a[i];
vector<int>pf(n + 1), sf(n + 1);
for (int i = 1;i < n;++i)pf[i + 1] = pf[i] + abs(a[i]);//前缀和(不含a1的|ai|),注意下标的计算
for (int i = n - 1;i >= 1;i--)sf[i - 1] = sf[i] - a[i];//-ai的后缀和,注意下标的计算
int ans = sf[0];
for (int i = 1;i < n;++i)ans = max(ans, a[0] + pf[i] + sf[i]);
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
我赛时没想到的点:
- |ai|
- 下标计算给自己绕晕了