【题解】IncDec Sequence

测试链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3043

题目描述

给定一个长度为 \(n\) 的数列 \({a_i}\),每次可以选择一个区间 \([l,r]\),使这个区间内的数都加一或者都减一。

问至少需要多少次操作才能使数列中的所有数都一样。并求出在保证最少次数的前提下,最终得到的数列有多少种。

输入格式

第一行一个正整数 \(n\)

接下来 \(n\) 行,每行一个整数,第 \(i+1\) 行的整数表示 \(a_i\)

输出格式

第一行输出最少操作次数

第二行输出最终能得到多少种结果

数据范围

测试时间限制 \(1000\,\textrm{ms}\),空间限制 \(1\,\textrm{GiB}\)

对于 \(100\%\) 的数据,\(n\le 100000\)\(0\le a_i< 2^{31}\)

分析

注意到这里用的是区间修改,而最后询问的是次数和方法数。我们考虑差分。

啥?不知道差分?

差分就是将一个数列 \({a_i}\) 相邻两项作差,得到一个新数列 \(\Delta{a_i}\)

对于原数列 \(a_i\),构造差分数列 \(\Delta a_i\),答案要求的就是 \(\forall i\in [1,n)\ \Delta{a_i}=0\)

而题目所要求的操作,就是给差分数列加上两项后,\({a_i}\ (0\le i\le n)\) 中两项,一项加一,另一项减一。

最小操作次数

注意到,若 \(a_i\ (0<i<n)\) 为正,则必须要减去至少 \(a_i\) 次。同理,如果 \(a_i\ (0<i<n)\) 为负,则必须至少加上 \(|a_i|\)

当两个“至少”同时达到时,就是最小操作次数。

即若 \(p=\sum\limits_{0< i< n\\a_i>0}^n a_i\)\(q=\sum\limits_{0< i< n\\a_i<0}^n |a_i|\),则最小操作次数就是 \(\max(p,q)\)

方案数

注意到一加一减的操作不会影响 \(\sum\limits_{i=0}^n a_i\),同时 \(\sum\limits_{i=1}^{n-1} a_i=0\),则 \(a_0 + a_n\) 为定值。

又因为会有 \(|p-q|\) 个区间有多余的操作,将这两个操作分给两个数,一共有 \(|p-q|+1\) 种方案。

那就是答案。

Code

#include <cstdio>
#include <cctype>
using namespace std;

typedef long long ll;

inline int read()
{
	int ch = getchar(), n = 0, t = 1;
	while (isspace(ch)) { ch = getchar(); }
	if (ch == '-') { t = -1, ch = getchar(); }
	while (isdigit(ch)) { n = n * 10 + ch - '0', ch = getchar(); }
	return n * t;
}

inline ll ab_max(ll a, ll b) { return (a > b)? a:b; }
inline ll ab_abs(ll a, ll b) { return (a > b)? a-b:b-a; }

int main()
{
	int n = read(), pre = read(), now;
	ll sum_pos = 0, sum_neg = 0;
	
	for (int i = 1; i < n; i++)
	{
		now = read();
		
		if (now > pre)
			sum_pos += now - pre;
		else if (now < pre)
			sum_neg += pre - now;
		
		pre = now;
	}
	
	printf("%lld\n%lld\n", ab_max(sum_pos, sum_neg), ab_abs(sum_pos, sum_neg) + 1);
	
	return 0;
}
posted @ 2020-03-03 12:38  5ab  阅读(125)  评论(0编辑  收藏  举报