题解:P17521 天外来物
题意简述
有 \(n\) 颗水晶,每颗水晶有权值 \(a_i\),取走一颗水晶时编号与它相邻的水晶的权值会变为原来的相反数。设计一种取水晶的顺序使得取走的权值最大。\(n\leq 2\times 10^5,-10^9\leq a_i\leq 10^9\)。
思路分析
观察样例可以发现基本都能取到绝对值之和。
容易得到当 \(n\) 与序列中负数个数的奇偶性相同时,至少取到一个负数;否则可以取所有正数。
证明
对于相邻两颗水晶 \(i,i+1\),如果 \(i\) 比 \(i+1\) 更早取走,则定向为 \(i\to i+1\);否则定向为 \(i+1\to i\)。
令 \(d_i\) 表示 \(i\) 的入度,即它旁边比它先取走的个数。采集它时,它被翻转了 \(d_i\) 次,所以最终取走的值为 \((-1)^{d_i}a_i\)。
每条边恰好贡献一个度数,所以 \(\sum d_i=n-1\)。
\(d_i\) 中奇数的个数为 \(k\equiv \sum d_i\equiv n-1\pmod 2\)。
如果我们希望全部取正,则需要满足:
- 对于 \(a_i<0\),\(d_i\) 为奇数;
- 对于 \(a_i>0\),\(d_i\) 为偶数。
所以 \(a_i\) 为负的地方应该满足 \(d_i=1\),即 \(k\) 等于序列中的负数个数,即个数为 \(c\)。
只需要判断 \(c\equiv n-1\pmod 2\) 即可。结论成立。
代码实现
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int T, n, a[N];
signed main(){
cin >> T;
while(T--){
cin >> n;
int cnt = 0, minn = 1e9; long long sum = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum += abs(a[i]), cnt += a[i] < 0, minn = min(minn, abs(a[i]));
}
if(n == 1) cout << a[1] << '\n';
else if(((n - cnt) & 1) == 0) cout << sum - 2 * minn << '\n';
else cout << sum << '\n';
}
return 0;
}
时间复杂度 \(O(n)\)。

浙公网安备 33010602011771号