Solution IncDec Sequence
题目大意:给定一个序列,你可以将一段子序列集体(+1)或(-1),求最小的操作次数使得所有数相等,以及操作方案数
差分
分析:
区间加减不好考虑,我们可以考虑差分
令原数组(val[0] = 0),差分数组(d[i] = val[i] - val[i - 1])
然后问题就变成了,给你一个序列,每次可以将(1)个数(+1)同时将另一个数(-1),求最小操作次数使得所有数下标不为(1)的数为(0)
我们发现,这种方式可以同时改变(2)个数,应当优先采用
设(q = sum d[i] quad | quad d[i] > 0 ; and ; i eq 1),(p = sum d[i] quad | quad d[i] < 0 ; and ; i eq 1)
这种方法最多采用(min(p,q))次
然后考虑剩下的,这个需要(|p-q|)次
所以需要(min(p,q) + |p -q| = max(p,q))次
方案:
方案取决于剩下的数,显然剩下的都和(d[1])同号了,有些可以作用于(d[1]),有些可以作用于(d[n + 1]),所以有(|p - q| + 1)种不同的(d[1])取值,所以方案有(|p - q| + 1)种
#include <algorithm>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
ll val[maxn],d[maxn],sum,vsum;
int n;
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++)scanf("%lld",val + i);
for(int i = 2;i <= n;i++){
d[i] = val[i] - val[i - 1];
if(d[i] > 0)sum += d[i];
else vsum -= d[i];
}
printf("%lld
",max(sum,vsum));
printf("%lld
",abs(sum - vsum) + 1);
return 0;
}