>>题目链接
题目描述
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
输入格式
第一行输入正整数n。
接下来n行,每行输入一个整数,第i+1行的整数代表ai。
输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
数据范围
0<n≤1
0≤ai<2147483648
输入样例:
4
1
1
2
2
输出样例:
1
2
#include <algorithm>
#include <iostream>
#define Max(a, b) ((a > b) ? (a) : (b))
#define Min(a, b) ((a < b) ? (a) : (b))
using namespace std;
const int arrN{100005};
int arr[arrN];
int main(int argc, char **argv)
{
int N;
cin >> N;
for (int i = 0; i != N; ++i)
cin >> arr[i];
auto positive{0LL}, negative{0LL};
for (int i = N - 1; i; --i)
{
arr[i] -= arr[i - 1];
if (arr[i] > 0)
positive += arr[i];
else if (arr[i])
negative -= arr[i];
}
cout << Max(positive, negative) << endl;
cout << abs(positive - negative) + 1 << endl;
return EXIT_SUCCESS;
}
- 想要得到所有数都一样,也就是要使差分序列的 2 - n 项全为 0。而第 1 项代表第一个数的大小,第 n+1 项代表第 n 个数的相反数,改变第1项或者第 n+1 项只会让数列整体变大或变小,并不影响数列相同。
- 计算差分序列,记录差分序列中正数和负数的个数
- 区间内都加一 / 减一也就是对差分序列中区间两侧端点加一减一,每次可以让差分序列中的两个数一个 +1 另一个 -1
- 最佳情况是在差分序列中 2 - n 项中任取一对正负数,每次就会消掉一个正数及一个负数。这最多可以取Min( 正数个数,负数个数 )次。
- 差一些的情况是取 2 - n 中的一个正数/负数,另一个取差分序列的第 1 项或第 n+1 项,须进行 abs( 正数个数 - 负数个数 ) 次。
因此,最小的操作次数就是 Min( 正数个数,负数个数 )+ abs( 正数个数 - 负数个数 ) ,也就是 Max( 正数个数,负数个数 ) 次;
最终可能有多少种结果,只需要计算差分序列第一项或最后一项的可能结果个数即可,如 abs( 正数个数 - 负数个数 ) 次操作全都是取第一项,那么有可能这些操作都是加一,那么第一项将有 abs( 正数个数 - 负数个数 ) + 1 种可能。