尺取法
2015-08-10 14:52
253 查看
尺取法一般用来求解最大/最小区间问题。用两个指针代表区间的首尾,反复地推进区间的开头和末尾,来求取满足条件的最小/大区间,复杂度为O(n)。
当一个区间满足条件时,左指针推进,判断新区建是否满足条件,如果不满足条件,那么区间末尾向后扩展,直到满足条件为止。这样在区间推移过程中我们就得到了很多满足条件的区间,根据题意取最优即可。
当满足以下条件时,可以使用尺取法:若从
开始,至少要到
才能满足条件,即:最初满足条件的区间为
,则从
开始的最初满足条件的区间为
,必然有t≤t'。
例题: poj3061 Subsequence
设若从
开始总和最初不小于s时的连续子序列为
,这时
,所以从
开始总和最初大于s的连续子序列如果是
的话,则必然有t≤t'。所以可以用尺取法。
(1)以s = 0,t = 0,sum = 0初始化;
(2)只要依然有sum < S,就不断将sum累加
,并将t加1;
(3)如果(2)中无法满足sum >= S则终止,否则更新res = min(res, t - s + 1);
(4)将sum减去
,s增加1然后回到(2)。
由于t最多变化t次,故算法复杂度为O(n)。
代码如下:
当一个区间满足条件时,左指针推进,判断新区建是否满足条件,如果不满足条件,那么区间末尾向后扩展,直到满足条件为止。这样在区间推移过程中我们就得到了很多满足条件的区间,根据题意取最优即可。
当满足以下条件时,可以使用尺取法:若从
开始,至少要到
才能满足条件,即:最初满足条件的区间为
,则从
开始的最初满足条件的区间为
,必然有t≤t'。
例题: poj3061 Subsequence
设若从
开始总和最初不小于s时的连续子序列为
,这时
,所以从
开始总和最初大于s的连续子序列如果是
的话,则必然有t≤t'。所以可以用尺取法。
(1)以s = 0,t = 0,sum = 0初始化;
(2)只要依然有sum < S,就不断将sum累加
,并将t加1;
(3)如果(2)中无法满足sum >= S则终止,否则更新res = min(res, t - s + 1);
(4)将sum减去
,s增加1然后回到(2)。
由于t最多变化t次,故算法复杂度为O(n)。
代码如下:
#include <cstdio> using namespace std; #define N 100005 #define min(a, b) (a) < (b) ? (a) : (b) int a , sum ; int main(){ int tc, n, s; scanf("%d", &tc); while(tc --){ scanf("%d %d", &n, &s); sum[0] = 0; for(int i = 1; i <= n; ++i) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i]; int beg = 1, en = 1, ans = N; while(en <= n){ int tmp = sum[en] - sum[beg - 1]; if(tmp >= s) ans = min(ans, en - beg + 1), ++beg; else ++en; } printf("%d\n", ans == N ? 0 : ans); } return 0; }
相关文章推荐
- SODBASE CEP学习进阶篇(六):实现反压和流限速
- redis CONFIG REWRITE介绍
- 用JavaScript(js)对时间格式化
- Android aapt使用小结
- python实现JAVA源代码从ANSI到UTF-8的批量转换方法
- LINUX下SVN系统的搭建
- HDU - 1878 - 欧拉回路
- 关系数据库还是NoSQL数据库
- easyUI设置textbox的值
- vs 检测内存泄漏
- memcached安装及java应用使用memcached
- solaris 10u11 安装vim7.4
- 主机命令执行
- REM
- 九度OJ 题目1437:To Fill or Not to Fill
- [洛谷U871]building
- 写博客的理由
- 更改maven使用的java版本(Mac)
- 本地IP获取
- PHP 两个等号 和 三个等号的区别