题意:
有一个长度为n的序列,你可以进行两种操作,选去某个数加1或者减1。那我进行这个操作的目的,是为了让这个序列保持以下这种状态:
1)这个数列进行到任意一项的前缀和都不用允许为0;
2)这个数列进行到第 i 项的前缀和与第 i+1 项的前缀和符号必须不同。
求,最少操作步数。
思路:
这题就是先对前缀和的第一项为正还是为负分别进行一次复杂度为O(n)的讨论,由于这道题我代码的注释写的异常详细,思路就不赘述了,直接贴我AC代码啦 >~<
AC代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxx = 1e5 + 7; const ll Inf = 1ll << 60; ll n; ll a[maxx]; ll ans = Inf; int main() { cin >> n; for(int i = 1; i <= n; i++) cin >> a[i]; bool flg = 0; ll sum = 0, res = 0; for(int i = 1; i <= n; i++) { // + - + - + - ... sum += a[i]; if(!flg) { // sum为正, flg = 0 if(sum <= 0) { //若当前sum <= 0, 将sum变为1 res += 1 - sum; //sum变为1所需要的花费是 1 - sum (sum <= 0) sum = 1; } } else { // sum为负, flg = 1 if(sum >= 0) { //若当前sum >= 0, 将sum变为-1 res += sum + 1; //sum变为-1所需花费是 sum + 1 (sum >= 0) sum = -1; } } flg ^= 1; //flg变号, 按位异或 } ans = min(ans, res); sum = res = 0; flg = 0; for(int i = 1; i <= n; i++) { // - + - + - + ... sum += a[i]; if(!flg) { //sum为负, flg = 0 if(sum >= 0) { //与上一次进行的O(n)操作同理 res += sum + 1; sum = -1; } } else { //sum为正, flg = 1 if(sum <= 0) { //与上一次进行的O(n)操作同理 res += 1 - sum; sum = 1; } } flg ^= 1; } ans = min(ans, res); cout << ans << endl; }