小蓝的操作————(java)差分数组
逆天老是忘记考虑数据的范围最坏情况下要操作10的5次方* 10 的5次方/2 超出int了
下次不管三七二十一直接加纳 long!!!!!!!!!!!!
以后我看见这种 我就用long 来计算输出结果 ,妈妈再也不用担心我的代码超时了
1.小蓝的操作 - 蓝桥云课
emm,上次这个没有听懂直接跳过了,这次回来仔细的又看了一遍
思路是什么呢,要把所有输入的数字都变成一
正常思路的话就是先把连续的不含1的序列给减去任意一个数字,保证减完之后有一个数字等于一
然后就需要把这个连续的序列给分开了,因为中间产生1 了
子序列也是同理,给每个子序列不断的减一指导,子序列中某一个数等于1 在拆开,再减,最后你会发现拆的子序列都只剩一个元素了
比如途中的子序列3 5 2 7
只能减去一次1了
变成了 2 4 1 6
拆分 2 4 和 6 两个子序列
然后2 4 又只能减去一次1
变成1 3
是不是就剩3 了 3再减去两次1
6再减去5次1 然后就变成了1 了
所以总次数 = 1 + 1 + 2 + 5 =9
你会发现是不是不用考虑小的数
然后的话我们用差分的思想来看
b[i] = a[i] -a[i-1]
将原数组转化为差分数组等于
1 2 4 -3 5 -6
是不是刚好差分数组中的所有的正数加在一起再减去1就是答案了
为什么呢
b[i]<=0是不是等价于 a[i]<=a[i-1]
这种情况是不是类似于5 2 这里
这里计算最小次数的话就不用考虑2了
后面的数比前面的数字小,是不是就是说明在后面的那个数变成1之后前面的那个数字才会变成1
这意味着什么呢?
也就是说可以把a[i]和a[i-1]看作是一起操作的,
直到a[i]变成1 a[i-1]仍然大于等于1
一起操作的相邻的两个数构成的序列 中是不是只要考虑更大的就行了,你说对吧
不管谁在前谁在后,
只要考虑大的那个变成1 需要操作的次数就行了,
因为大的元素,那个数的操作次数是不是也包含了小的数的操作次数
问题又来了,
怎么只考虑大的那个的操作次数呢
是不是只需要考虑差分数组中大于0的部分
小于0 的部分的操作次数是和大于0 的操作次数是有共用 的部分的
然后因为差分数组第一个数一定是等于原数组第一个数的
差分数组的第一个数是大于等于1 的,
所以最小操作次数就是差分数组中所有大于0 的数字之和
哎,你会发现答案不对
那就对了
因为你忽略了第一个元素多加了1
题目说一定有解,
而且操作只能是减法
所以原数组的第一个数一定是大于等于1 的
所以差分数组的第一个数也一定是大于等于1 的
假如第一个元素是1 ,那第一个元素是不是不用操作
也就是次数是0
但是上面的计算是怎么计算的呢,把每一个大于0 的差分数组的元素都加在了一起
那你这个时候多加了1
是不是就得减去1 呀
如果第一个元素大于1 那是不是操作次数也是多加了1
所以差分数组的第一个数要变成 1需要 多少次呢?
是不是得给总数在减去1
okok,盲猜你懂了!
上代码!!!
来言归正传,这是老师写的,我看了一遍,跟着写了一遍
package Lanqiao;
import java.util.Scanner;
/**
* @author zb
* date2025/3/23 15:29
*/
public class L3399 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n =in.nextInt();
// 原数组
int a[] = new int[n+10];
int b[] = new int[n+10];
for(int i =1; i<=n ; i++){
a[i] =in.nextInt();
b[i] =a[i]-a[i-1];
}
long sum = 0;
for(int i= 1 ;i<=+n; i++){
if(b[i]>0){
sum = sum+ b[i];
}
}
System.out.println(sum-1);
in.close();
}
}