这里
while (l + 1 < r)
{
int mid = (l + r + 1) >> 1;
if (check(mid)) l = mid;
else r = mid;
}
if (check(r)) printf("%d\n", r);
else printf("%d\n", l);
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid)) l = mid + 1;
else r = mid - 1;
}
printf("%d\n", r);
while (l < r)
{
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
while (l + 1 < r)
{
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid;
}
if (check(l)) printf("%d\n", l);
else printf("%d\n", r);
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid)) ans = mid, l = mid + 1;
else r = mid - 1;
}
printf("%d\n", ans);
这是一篇非常优秀的博客:https://blog.csdn.net/JarjingX/article/details/8180560
但是,在这里不讲这种过于形象的方式了,意会即可
来自这里
RMQ(区间最值查询) 是一个预处理O(nlogn)区间极值,O(1)查询任意区间极值的工具
主要思想就是区间dp出每个点起2的k次方的长度内的极值。运用大区间的极值由小区间得到,同时大区间的答案可以由小区间随意组合得到。比如我们已经预处理1为起点长度为4的答案,和2为起点向后4的答案,我们查询区间1到5的极值就可以比较1-4区间和2-5区间的答案来得到1-5的答案;
预处理的代码如下
f数组的意思是以i为起点2的j次方长度的区间的极值是多少
ST算法
void ST_prework()
{
memset(f, 10, sizeof(f));
for (int i = 1; i <= n; i++) f[i][0] = a[i];
int t = log(n) / log(2) + 1;
for (int j = 1; j < t; j++)
for (int i = 1; i <= n - (1 << j) + 1; i++)
f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
模拟一下:我们要得到f[1][1]就可以通过f[1][0]和f[2][0]得到 f[1][2]可以由f[1][1]和f[3][1]得到。由于我们是小区间得到大区间,所以比如求区间大小为8的时候,我们已经处理了所以4大小的区间了
查询极值如下
int ST_query(int x, int y)
{
int k = log(y - x + 1) / log(2);
return min(f[x][k], f[y - (1 << k) + 1][k]);
}
贪心是一种在每次决策时采取当前意义下最优策略的算法,因此,使用贪心算法要求问题的整体最优性可以由局部最优性导出。
常见的证明贪心算法正确性的手段有:
1.微扰(邻项交换)
2.范围缩放
3.决策包容性
4.反证法
5.数学归纳法
贪婪算法可解决的问题通常大部分都有如下的特性(看着还可以):(来自这里)
⑴ 有一个以最优方式来解决的问题。为了构造问题的解决方案,有一个候选的对象的集合。
⑵ 随着算法的进行,将积累起其它两个集合:一个包含已经被考虑过并被选出的候选对象,另一个包含已经被考虑过但被丢弃的候选对象。
⑶ 有一个函数来检查一个候选对象的集合是否提供了问题的解答。该函数不考虑此时的解决方法是否最优。
⑷ 还有一个函数检查是否一个候选对象的集合是可行的,也即是否可能往该集合上添加更多的候选对象以获得一个解。和上一个函数一样,此时不考虑解决方法的最优性。
⑸ 选择函数可以指出哪一个剩余的候选对象最有希望构成问题的解。
⑹ 最后,目标函数给出解的值。