【题解】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;
}
本文来自博客园,作者 5ab,转载请注明链接哦 qwq
博客迁移啦,来看看新博客吧 -> https://5ab-juruo.oier.space/