题目描述 Description
给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。
问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。
输入描述 Input Description
第一行一个正整数n
接下来n行,每行一个整数,第i+1行的整数表示ai。
输出描述 Output Description
第一行输出最少操作次数
第二行输出最终能得到多少种结果
样例输入 Sample Input
4
1
1
2
2
样例输出 Sample Output
1
2
数据范围及提示 Data Size & Hint
对于100%的数据,n=100000,0<=ai<2147483648。
来源:Nescafe 22
以下的版权属于lym:
对于带有“将一段区间内的每个数全部加上某个值”这种操作的题目,通常考虑差分原数列以简化情况,将对一段区间的操作转化为对某两个特定数的操作。
我们定义d_1 = a_1, d_i = a_i - a_{i-1} ( 2 ≤ i ≤ n ), d_{n+1} = 0(事实上,稍后我们会看到d_1和d_{n+1}的值并不重要),,可以发现,原题中的“将[l,r]内的数都加一或都减一”将对应“将d_l + 1,将d_{r+1} - 1”(或反之)的操作。
显然,题目中要求的a数列中的所有数全部相等的条件等同于使d_i = 0 ( 2 ≤ i ≤ n ),最后数列中的数即为d_1,而题目中的操作允许我们把d数列中的某个数+1,某个数-1。要将d数列中第二项至第n项全部变为0并使操作次数最少,首先我们将每个负数和每个正数配对执行操作,设d数列中第2至第n项所有正数分别求和得到的值为p,负数分别求和得到的值的*绝对值*为q,这一步的操作次数即为min{p,q}。此时还剩余和的绝对值为abs(p-q)的数没有变为0,每次操作我们可以将其与d_1或d_{n+1}配对进行操作,操作次数为abs(p-q),容易看出,最终d_1的可能取值有abs(p-q)+1种。因此,第一问的答案即为max{p,q},第二问的答案即为abs(p-q)+1。
tl;dr 差分原数列,正数分别求和负数分别求和,取绝对值较大的输出到第一行。输出abs(a[n]-a[1])+1到第二行。 ”
(tl;dr = too long;didn't read)
#include <cstdio> #define maxn 1000000 int a[maxn], b[maxn], n, i; long long x = 0, y = 0, ans; using namespace std; int main() { scanf("%d", &n); b[1] = 0; for (i = 1; i <= n; i++) scanf("%d", &a[i]); for (i = 2; i <= n; i++) { b[i] = a[i] - a[i - 1]; if (b[i] > 0) x += b[i]; else y -= b[i]; } if (x > y) {printf("%lld\n", x); ans = x - y;} else {printf("%lld\n", y); ans = y - x;} printf("%lld\n", ans + 1); return 0; }