挑战程序设计竞赛:尺取法
1. 题目介绍
1.1 题目
给定长度为n的数列整数a0,a1,…,an-1以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。
限制条件:
- 10 < n < 105
- 10 < ai <= 104
- S < 108
1.2 样例1
输入
n = 10
S = 15
a = { 5, 1, 3, 5, 10, 7, 4, 9, 2, 8 }
输出
2 (5+10)
1.3 样例2
输入
n = 5
S = 11
a = { 1, 2, 3, 4, 5 }
输出
3 (3+4+5)
2. 思路讲解
视频讲解总地址:传送门
题目介绍视频:传送门
2.1 二分法
二分法视频讲解:传送门
(摘抄自教材)由于所有的元素都大于零,如果子序列[s, t)满足as + … + at-1 >= S,那么对于任何的t < t’一定有as + … + at’-1 >= S。此外对于区间[s, t)上的总和来说如果令:
s
u
m
(
i
)
=
a
0
+
a
1
+
.
.
.
+
a
i
−
1
sum(i) = a_0 + a_1 + ... + a_{i-1}
sum(i)=a0+a1+...+ai−1
那么
a
s
+
a
s
+
1
+
.
.
.
+
a
t
−
1
=
s
u
m
(
t
)
−
s
u
m
(
s
)
a_s + a_{s+1} + ... + a_{t-1} = sum(t) - sum(s)
as+as+1+...+at−1=sum(t)−sum(s)
2.2 尺取法
尺取法视频讲解:传送门
(摘抄自教材)设以as开始总和最初大于S时的连续子序列为as + … + at-1,这时:
a
s
+
1
+
.
.
.
+
a
t
−
2
<
a
s
+
.
.
.
a
t
−
2
<
S
a_{s+1} + ... + a_{t-2} < a_s + ... a_{t-2} < S
as+1+...+at−2<as+...at−2<S
所以从as+1开始总和最初超过S的连续子序列如果是as+1 + … + at’-1的话,则必然有t<=t’。
代码视频讲解:传送门
3. 练习题
- Jessica’s Reading Problem (POJ No.3320)
- Bound Found (POJ No.2566)
- Sum of Consecutive Prime Numbers (POJ No.2739)
- Graveyard Design (POJ No.2100)
4. 附录:程序代码
4.1 Java
- 程序代码:传送门
4.2 C++
从教材上面直接摘抄的代码,所以没有输入数据处理,只有解法,供有需要的童鞋参考。
4.2.1 二分法
// 输入
int n, S;
int a[ MAX_N ];
int sum[ MAX_n + 1 ];
// O( nlogn )
void solve() {
// 计算sum
for ( int i = 0; i < n; i++ ) {
sum[ i + 1 ] = sum[ i ] + a[ i ];
}
if ( sum[ n ] < S ) {
// 解不存在
printf( "0\n" );
return;
}
int res = n;
for ( int s = 0; sum[ s ] + S <= sum[ n ]; s++ ) {
// 二分法查找t
int t = lower_bound( sum + s, sum + n, sum[ s ] + S ) - sum;
res = min( res, t -s );
}
printf( "%d\n", res );
}
4.2.2 尺取法
// O(n)
void solve() {
int res = n + 1;
int s = 0, t = 0, sum = 0;
for (;;) {
while ( t < n && sum < S )
sum += a[ t++ ];
if ( sum < S ) break;
res = min( res, t - s );
sum -= a[ s++ ];
}
// 解不存在
if ( res > n )
res = 0;
printf( "%d\n", res );
}
5. 附录:拓展阅读
6. 参考资料
- 《挑战程序设计竞赛(第2版)》,(日)秋叶拓哉 等著,人民邮电出版社;
7. 免责声明
※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;