一、枚举
- 一一列举
- 不重复、不遗漏
优化枚举的基本思路:——减少枚举次数
- 1、选择合适的枚举对象
- 2、选择合适的枚举方向——方便排除非法和不是最优的情况
- 3、选择合适的数据维护方法——转化问题
eg:数列求和问题
给你一个数列{an}(1≤n≤100000),有q(1≤q≤100000)次询问,每次询问数列的第li个元素到第ri个元素的和。
- 优化枚举---将对区间的查询变为对区间端点的查询
前缀和
- sum[i]存储前i个数的和,那么sum[i] = sum[i-1] + a[i]
- 当我们要查询第li个元素到第ri个元素的和时,用sum[ri] - sum[li-1]即可
- 这样单次查询的复杂度是O(1)的,总复杂度是O(n+q)的
sum[1]=a[1];
for(int i=2;i<=n;i++)
sum[i]=sum[i-1]+a[i];
eg:数列修改问题
给你一个数列{an}(1≤n≤100000),有q(1≤q≤100000)次修改,每次把数列中的第li到第ri的每个元素都加上一个值ki,求所有的修改之后每个数的值。
- 考虑在区间加的过程中有什么值是在区间端点处发生了变化而区间内是没有变化的
差分
- 当我们对第li个到第ri个数加上ki时,第li个数与第li-1个数的差值增加了ki,第ri+1个数与第ri个数的差值减少了ki,而区间内部的相邻两个数的差值是不变的!
- 所以我们可以用数组delta[i]来维护第i个数和其前一个数的差值,(可以默认第一个数前面有一个0),然后当需要将[li,ri]区间的每一个数+ki时,只需要修改delta[li]和delta[ri+1]即可。
- 在所有的修改操作进行完之后,我们再对delta[i]求一次前缀和,就可以得到数列的每个元素的值了
- 用数组delta[i]来维护第i个数和其前一个数的差值的办法叫做差分。
delta[1]=a[1];
for(int i=2;i<=n;i++)
delta[i]=a[i]-a[i-1];
差分和前缀和是一对对称的操作(即对差分数组求前缀和就是原数组,对前缀和求差分也会得到原数组)
贪心算法
- 贪心算法(又称贪婪算法)是指:在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
- 能够使用贪心算法的问题都是能严格证明贪心出的局部最优解就是所求的全局最优解的。
- 每次都选看起来最好的!