算法分析:
差分解决一段区域同时增加或减少的问题
给区间【L,R】上都加上一个常数c,则b[L] += c , b[R + 1] -=c
-
求出a的差分序列b,其中b1 = a1,b(i) = a(i) - a(i - 1) (2 <= i <= n)。令b(n + 1) = 0,题目对序列a的操作,相当于每次可以选出b1,b2…b(n + 1)中的任意两个数,一个加1,另外一个减一。目标是把b2,b3,…bn变为全0。最终得到的数列a就是由 n 个 b1 构成的
-
任选两个数的方法可分为四类
1、2 <= i , j <=n(优先)
2、i = 1, 2 <=j <=n
3、2 <= i <= n , j = n + 1
4、i = 1, j = n + 1(没有意义) -
设b2,b3....bn中正数总和为p,负数总和的绝对值为q。首先以正负数匹配的方式尽量执行1类操作,可执行min(p,q)次。剩余|p - q|个为匹对,每个可以选与b1或b(n + 1)匹配,即执行2 或 3 类操作,共需|p - q|次
-
综上所诉,最少操作次数为min(p,q) + |p - q|。根据|p - q|次第2、3类操作的选择情况,能产生|p - q| + 1中不同的b1的值,即最终得到的序列a可能有|p - q| + 1 种
import java.util.Scanner;
public class Main {
static int N = 100010;
static int[] a = new int[N];
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
for(int i = 1; i <= n;i ++) a[i] = scan.nextInt();
//构成差分序列
for(int i = n;i >= 2;i --) a[i] -= a[i - 1];
long p = 0;//b2到bn的正数总和
long q = 0;//b2到bn的负数总和
for(int i = 2;i <= n;i ++)
{
if(a[i] > 0) p += a[i];
else q -= a[i];//注意这里a[i]是负数,所以需要q = q - q[i]变成整数
}
System.out.println(Math.min(p, q) + Math.abs(p - q));
System.out.println(Math.abs(p - q) + 1);
}
}
如果差分序列是 5 2 0 0 0为什么是三种结果
全5,6,7三种情况
都是两次操作
所以为啥不是max( p , q ) 呢
这个是正数负数相互抵消
再怎么抵消也是等价的好吧
抵消肯定是以最小的为有效啊,比如说有15个-1 有20个+1 那抵消完不就只剩下5个+1了 只能抵消最小的15
有没有可能我说的意思是是$min(p, q) + \|p - q\| == max( p, q )$
你说得对
大佬们,为啥剩余的是abs(p - q) 个呢?假如差分数列未1,-3, 4, -2, 5, -7那我先把所有正数变为0然后数列为
1, -3, 0, -2, 0, -7按结论是说还需要操作abs(p - q) == 3次,可是操作3次并不能把他们变为全0数列啊
差分的操作是一个数加一一个数减一啊,你把正数变成0了,那负数不用变么?
orz
讲的非常的好,零基础也看懂了
请问,这种方式只能确定这样贪心得到的步数最少,但不能确定这是唯一能让步数最少的方式,所以后面对于种数的讨论,如果这样贪心不是唯一的方案,种数不就会少吗,请问这里怎么证明,谢谢
所以说到底为什么b[L] += c , b[R + 1] -=c就行
这就是把书上的内容copy了一遍啊
太细致了
想问一下 为什么一定要把a[i]里面的数全部变成a[1]?这样好像不能保证一定操作数最小吧
课代表,赞
写的很详细,理解了。赞一个
可是这道题是最高的牛,不是incdec序列啊 ..
已修改已修改
可是在你的题解里面点原题链接还是最高的牛啊…
谢谢大哥!已经再次修改hh