codeforces B. Roma and Changing Signs 解题报告
题目链接:http://codeforces.com/problemset/problem/262/B
题目意思:给出 n 个数和恰好一共要做的操作总数k。通过对n个数进行k次操作,每次操作可以把a[i] 转化为 -a[i](当然也可以对同一个数进行 <= k次操作)。问k次操作之后,整个序列的和最大为多少。
首先要知道整个序列中数的分布是如何的,有3种情况:1、都为正数。此时k次操作只需要考虑序列中第一个数,因为它是最小的。 2、都为负数。容易想到,要尽可能把最小的负数变为相应的正数,如果变完之后,还没有到k次操作,那么就考虑负数和正数的交接处,看究竟是哪个数较小。
3、负正都有。这种情况和第2种情况处理类似。
另外要注意n = 1,即整个序列只有一个数的情况。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 7 const int maxn = 1e5 + 10; 8 int a[maxn]; 9 10 int main() 11 { 12 int n, k, i, ans, cnt; 13 while (scanf("%d%d", &n, &k) != EOF) 14 { 15 cnt = ans = 0; 16 for (i = 1; i <= n; i++) 17 { 18 scanf("%d", &a[i]); 19 ans += a[i]; 20 } 21 if (a[1] >= 0 && a[n] >= 0) // positive 22 { 23 if (k % 2) 24 ans -= 2 * a[1]; 25 } 26 else // negative or ne+po 27 { 28 for (i = 1; i <= n; i++) 29 { 30 if (a[i] < 0 && cnt < k) 31 { 32 ans -= 2 * a[i]; 33 cnt++; 34 } 35 else if (cnt >= k || a[i] >= 0) 36 break; 37 } 38 if (cnt != k) 39 { 40 k -= cnt; 41 if (n != 1) 42 { 43 a[i] = (-a[i-1] > a[i] ? a[i] : -a[i-1]); // 正负交接处哪个数更小 44 if (k % 2) 45 ans -= 2 * a[i]; 46 } 47 else // 整个序列只有1个数的情况 48 if (k % 2) 49 ans += 2 * a[1]; 50 } 51 } 52 printf("%d\n", ans); 53 } 54 return 0; 55 }