增减序列

 

 贪心加差分,不愧是拔高的题目,好题

主要有一点不好理解,为什么最终所有可能的序列是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 }

 

posted @ 2020-11-04 10:50  kyk333  阅读(279)  评论(0)    收藏  举报