poj 3061 Subsequence 尺取法

缘起

日常水题 poj 3061 Subsequence

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
一个正整数数列,由N(10 < N < 100000)个正整数构成. 每个元素<=10000. 给出一个正整数S(<1亿). 写一个程序找到最小的长度使
得序列的连续片段和>=S

【输入】
多样例
每个样例给出N和S,然后给出N个正整数. 处理数据到文件尾

【输出】
最小长度(办不到的话,输出0)

【样例输入】
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5

【样例输出】
2
3

【限制】
Time limit 1000 ms
Memory limit 65536 kB

【来源】
Southeastern Europe 2006

下面尺取的思路是,尺取虫的头部先动,直至>=s(满足条件)然后更新一波答案, 然后尺取虫的尾部再动,直至<s(不满足条件),然后再更新一波答案 . 一般这就是尺取法的思路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//#include "stdafx.h"

#include <stdio.h>
#include <string.h>
//#define LOCAL

int n,s,a[100005];

int cq() // 尺取法, 头尾永不止步, 所以复杂度是O(N)
{
int lo = 0, hi = 0, i, ans = 1e8, sum = a[0];
while(hi<n)
{
while(hi<n && sum<s) // 尺取虫开始爬行, 首先是头部开始爬行
{
hi++;
if (hi==n)
{
break;
}
sum+=a[hi];
}
if (sum<s) // 说明hi=n了
{
break;
}
// 到这里之后, hi<n ,sum>=s
if (hi-lo+1<ans) // 更新一波 ans
{
ans = hi-lo+1;
}
while(lo<=hi&& sum>=s) // 尺取虫尾巴开始爬行了
{
sum-=a[lo];
lo++;
}
if (lo>hi)
{
return 1; // 说明一个数就能>=s, 所以最小是1
}
// 说明lo<=hi&&sum<s
if (ans>hi-lo+2)
{
ans = hi-lo+2;
}
}
return ans==1e8?0:ans;
}

int main()
{
#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
//freopen("d:\\my.out", "w", stdout);
#endif
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &s);
for (int i = 0; i<n; i++)
{
scanf("%d", a+i);
}
printf("%d\n",cq());
}
return 0;
}

ac情况

Status Accepted
Time 79ms
Memory 492kB
Length 919
Lang C++
Submitted 2019-08-23 14:51:43
Shared
RemoteRunId 20791758