贪心加差分,不愧是拔高的题目,好题
主要有一点不好理解,为什么最终所有可能的序列是abs(pos - neg) + 1种
pos和neg中的小者就是b[i]和b[j]一正一负配对时+1-1操作的数量
剩余的|pos-neg|就是落单的差分序列中的正数或负数b[k],这些差分序列剩余的正数或负数b[k]可以通过与差分序列
中b[1]或b[n+1]进行+1-1操作使b[k]逐步变到0,而这些b[k]如果与b[1]配对进行+1-1的操作则会影响常数列的初值a[1],
从而影响最终的常数列。所以常数列的最多可能有|p-q|+1种(算上前面min(neg,pos)次不影响常数列初值的操作),最少可能有
1种,就是差分序列中剩余的b[k]都与b[n+1]配对进行+1-1的操作,也就是一次也不和b[1]配对
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 100010; 5 int a[N]; 6 int main() { 7 int n; 8 cin >> n; 9 for (int i = 1; i <= n; i++) { //读入原数组 10 cin >> a[i]; 11 } 12 for (int i = n; i > 1; i--) { //把a数组变为它自己的差分数组 13 a[i] -= a[i - 1]; 14 } 15 ll pos = 0; //存储所有正数的和 16 ll neg = 0; //存储所有负数的和 17 for (int i = 2; i <= n; i++) { 18 if (a[i] > 0) { 19 pos += a[i]; 20 } else { 21 neg -= a[i]; //注意此时的a[i]是负数,所以此处是减等。如果写加等,最后需要neg=abs(neg) 22 } 23 } 24 //neg = abs(neg); //若上面写+=,此处需要取消注释 25 cout << min(pos, neg) + abs(pos - neg) << endl; //操作次数 26 cout << abs(pos - neg) + 1 << endl; //方案数 27 return 0; 28 }