Inc和Dec是 increase ,decrease两个单词的缩写所以这个问题又叫增减序列。
这个问题是这样的:
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
思路:
我们观察到,题目要求我们对一个区间中的数加一或者减一,很容易想到差分。
差分是什么呢?
差分就是前缀和的逆运算,前缀和是原数组前 n 项的和,差分就是 差分序列的前n项和是原数组的第n项。
假设a是原序列,b是差分序列。
差分序列可以由原数组求得: 。
那我们怎么样对整个序列用差分来操作呢?
假设我们对[l,r]这个区间的数都加上c,我们可以
用两个数的操作来改变整个序列的操作。
对于这道题:
题目要求原序列每个数都一样,可以转换为差分序列 b2 到 bn 都为0,需要最少多少步,
在最少的步数下b1有多少种情况。
由于差分序列对 l 和 r+1 两个数来操作,所以差分序列最大达到了n+1.由于要在差分序列的n个数里面挑两个进行操作,可以分为以下四种情况:
1.对b2 到 bn 中选两个,一个+1,一个-1.
2.选定b1,然后在 b2 到 bn中选一个+1或者-1。
3.选定bn+1,然后再b2到bn中选一个+1或者-1.
4.选中整个序列+1或者-1没有意义。
目标是将b2到bn所有的数都变为0.
我们假设差分序列 b2 到 bn 中所有正数的和为p,所有负数的和为q,
优先第一种操作,因为第一种操作可以同时改变两个数,当所有的正数或负数都变为0之后,我们在2和3中选择。
最少操作步数为
第一种操作 第二,三种操作
在最少操作步数下,b1的种类与第二种操作的次数有关,当第一种操作结束之后,有 种操作,分配给2和3,可知第二种操作可以有
种
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=100010;
int a[N],b[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) b[i]=a[i]-a[i-1];
long long p=0,q=0;
for(int i=2;i<=n;i++)
{
if(b[i]>0) p+=b[i];
else q-=b[i];
}
cout<<min(p,q)+abs(q-p)<<endl;
cout<<abs(p-q)+1<<endl;
return 0;
}