IncDec Sequence
Time Limit:10000MS Memory Limit:165536K
Total Submit:5 Accepted:0
Case Time Limit:1000MS
Description
给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。
问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。
Input
第一行一个正整数n
接下来n行,每行一个整数,第i+1行的整数表示ai。
Output
第一行输出最少操作次数
第二行输出最终能得到多少种结果
Sample Input
4
1
1
2
2
Sample Output
1
2
对于这种一段区间加减的题,我们首先把它差分,得出一个序列d[0..n](d[0] = a[1], d[i] =a[i]-a[i+1],d[n]=0)这样我们就将原问题转换为同时在一个位置上+1,另一个位置-1,问使d[2..n-1]全变成0,需要多少次,d[0]有多少种取值; 首先我们将每个负数和每个正数配对执行操作,设d[1..n-1]项所有正数分别求和得到的值为p,负数分别求和得到的值的*绝对值*为q,这一步的操作次数即为min{p,q}。此时还剩余和的绝对值为abs(p-q)的数没有变为0,每次操作我们可以将其与d[0]或d[n]配对进行操作,操作次数为abs(p-q),容易看出,最终d[0]的可能取值有abs(p-q)+1种。因此,第一问的答案即为max{p,q},第二问的答案即为abs(p-q)+1。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int maxn = 110000; int a[maxn], n; void init(){ scanf("%d", &n); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); } void work(){ long long x = 0, y = 0; for (int i = 1; i < n; i ++){ int tmp = a[i] - a[i + 1]; if (tmp >= 0) x += tmp; else y += tmp; } y = abs(y); cout <<max(x, y) <<endl; cout <<max(x, y) - min(x, y) + 1<<endl; } int main(){ init(); work(); return 0; }