给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
输入格式
第一行输入正整数 n。
接下来 n行,每行输入一个整数,第 i+1 行的整数代表 ai。
输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
数据范围
0<n≤105
0≤ai<2147483648输入样例:
4 1 1 2 2
输出样例:
1 2
这道题很简洁,就是将数组内的数进行加1或减1的操作,让数组内的数相等,输出最少操作次数以及其可能得结果。
这道题很容易想到,为了改变数组某段区间的数,我们可以想到差分的性质,差分数组内每个元素都是与前一位作差得到,而如果擦还分数组内的数全为0,那么前一个数就会等于这个数,所以我们把题意转变成如何让差分数组内的数全改变成0?
首先差分数组的性质是在[l,r]区间内让g[l] += 1 , g[r + 1] -= 1就可以使这个区间范围内的数+1,那么我们就可以找正负进行配对,其次剩下的可以与差分数组首元素或者尾元素配对,不会改变原数组的值。
注意:这里的g[1] = a[1]是保持不变的,不被修改,以至于后边的数都别修改为0,其原数组都等于a[1]
那么这道题就转变成求出差分数组正数和p与负数和q,然后选出最大的数并加上abs(p-q)就可以得到最小的操作次数。(这里优化结果min(p,q) + abs(p - q) = max(p,q))
而可能得结果不就是1 + abs(p - q) = g[1]本身的值+abs(p - q)这么多的情况,因为最后的值是根据b[1]决定的,其数的种类就是其本身的值(1) + abs(p - q)中情况。
#include <iostream>
using namespace std;
typedef long long ll;
const ll N = 1000000;
ll a[N],g[N];
int main()
{ll n;cin >> n;for(ll i = 1;i <= n;i++){cin >> a[i];}for(ll i = 2;i <= n;i++){g[i] = a[i] - a[i - 1];//差分数组}ll z = 0;//正数和ll f = 0;//负数和//当差分数组内值=0,意味着原数组内的数改后相等//优先正负配对//差分数组的头尾元素的修改不影响原数组,所以与头尾配对可以单独修改for(ll i = 2;i <= n;i++){if(g[i] > 0){z += g[i];}else if(g[i] < 0){f -= g[i];}}cout << min(z,f) + abs(z - f) << endl;//操作次数(正负配对+单beng出来的)cout << 1 + abs(z - f);//可能情况return 0;
}