P4552 IncDec Sequence|差分经典贪心题完整博客题解

一、题目题意

请添加图片描述

题目规则

给定长度为 $n$ 的序列 $a_1,a_2,\dots,a_n$,支持两种操作:

  1. 选定区间 $[l,r]$,区间内所有数字 $+1$;
  2. 选定区间 $[l,r]$,区间内所有数字 $-1$。

要求输出两个答案:

  1. 将整个数列所有数字变为相同值的最少操作次数
  2. 在保证操作次数最少的前提下,最终相同数字一共有多少种可能。

样例解读

输入:

4
1
1
2
2

原数组 $a=[1,1,2,2]$
差分数组 $b=[1,0,1,0]$
统计正数差分总和 $p=1$,负数差分绝对值总和 $q=0$
最少操作次数 $\max(1,0)=1$;可行答案种类 $|1-0|+1=2$,对应输出 12
请添加图片描述

二、核心算法:差分 + 贪心

1. 差分定义

定义差分数组 $b$,其中:
$$b_1 = a_1,\quad b_i = a_i - a_{i-1}\quad (i\ge2)$$

原数组区间操作等价于差分单点修改:

  • 区间 $[l,r]$ 全部 $+1$:$b[l] += 1,\ b[r+1] -=1$(若 $r+1\le n$);
  • 区间 $[l,r]$ 全部 $-1$:$b[l] -= 1,\ b[r+1] +=1$(若 $r+1\le n$)。

2. 目标转化

题目要求所有数字相等,等价于:原数组差分 $b_2,b_3,\dots,b_n$ 全部变为 $0$。
因为若 $b_2=b_3=\dots=b_n=0$,则 $a_1=a_2=\dots=a_n$。
$b_1$ 可以是任意整数,对应最终统一后的数值。

3. 最少操作次数推导

设:

  • $p$:$b_2\sim b_n$ 中所有正数的总和;
  • $q$:$b_2\sim b_n$ 中所有负数的绝对值总和。
  1. 正数差分需要用区间 $+1$ 操作抵消,总消耗 $p$ 次;
  2. 负数差分需要用区间 $-1$ 操作抵消,总消耗 $q$ 次;
  3. 正负操作可以互相复用一部分区间,最少总操作次数为 $\max(p,q)$。

4. 可行最终值的数量推导

$b_1$ 可以自由变化,变化范围长度为 $|p-q|$,因此总可行种类:
$$|p - q| + 1$$
请添加图片描述

三、完整AC代码

#include <iostream>
using namespace std; 
typedef long long LL;

const int N = 100010;
int a[N], b[N];

int main() {
	int n;
	cin >> n;
	for(int i=1; i<=n; i++) cin >> a[i];
	
	// 构建差分数组
	for(int i=1; i<=n; i++) b[i] = a[i]-a[i-1];
	
	LL p = 0, q = 0;
	// 统计b[2]~b[n]正负总和
	for(int i=2; i<=n; i++){
		if(b[i]>0) p+=b[i];
		else q+=abs(b[i]);
	}
	
	// 最少操作次数、可行数值种类
	cout<<max(p,q)<<'\n'<<abs(p-q)+1;
	return 0;
}

四、分步完整解题流程

步骤1:读入原数组

读取序列长度 $n$,循环存入数组 $a[1\sim n]$。

步骤2:构建差分数组

循环计算 $b[i] = a[i]-a[i-1]$,得到完整差分序列。
我们只需要处理下标 $2\sim n$ 的差分,目标是将它们全部归零。

步骤3:统计正负差分总和

遍历 $i=2$ 到 $n$:

  • 若 $b[i]>0$,累加到正数总和 $p$;
  • 若 $b[i]<0$,累加其绝对值到 $q$。

步骤4:计算并输出答案

  1. 最少操作次数:$\max(p,q)$;
  2. 最终相同数字的方案数:$|p-q| + 1$;
    分行打印两个结果。

五、代码分段详解

1. 常量与变量定义

typedef long long LL;
const int N = 100010;
int a[N], b[N];
  • $N=100010$:适配题目数据范围 $n\le 10^5$;
  • a[]:存储原始输入数列;b[]:差分数组;
  • LL p,q:防止累加数值过大,使用长整型存储正负差分总和。

2. 读入数组 + 差分构造

for(int i=1; i<=n; i++) cin >> a[i];
for(int i=1; i<=n; i++) b[i] = a[i]-a[i-1];

标准差分构造公式,$a[0]$ 默认初始为0,不影响计算。

3. 统计正负差分总和

LL p = 0, q = 0;
for(int i=2; i<=n; i++){
	if(b[i]>0) p+=b[i];
	else q+=abs(b[i]);
}

只遍历 $b_2$ 到 $b_n$,这部分差分需要全部清零;$p$ 记录所有正数差分总和,$q$ 记录负数差分绝对值总和。

4. 输出两组答案

cout<<max(p,q)<<'\n'<<abs(p-q)+1;
  1. $\max(p,q)$:最少区间操作次数;
  2. $|p-q|+1$:满足最少操作前提下,最终相同数字的总种类。

六、题型总结

  1. 模型定位:差分区间操作经典贪心模板题,是差分入门必做题;
  2. 核心转化:区间修改 → 差分单点修改,数列全相等 → 后缀差分全部为0;
  3. 两个结论记忆点:
    • 最少操作次数 = 正差分总和、负差分绝对值总和二者最大值;
    • 最终统一数值方案数 = 两个总和差值的绝对值 $+1$;
  4. 拓展延伸:差分可快速解决大量区间增减、最小操作次数类问题。

posted on 2026-07-13 19:00  5iCode  阅读(7)  评论(0)    收藏  举报

导航