Poj-3061 Subsequence(经典尺取)

本文介绍了一种利用尺取法解决特定序列问题的方法,通过给定的正整数序列及目标值S,寻找序列中连续元素子序列的最小长度,其和大于或等于S。

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.
Sample Input
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
Sample Output
2
3

翻译:
给出了N个正整数(10<N<100000)的序列,每个正整数小于或等于10000,一个正整数S(S<109)。写一个程序求序列中连续元素的子序列的最小长度,其和大于或等于S。

尺取法的分析:尺取法在cf用“two pointers"来表示,即它使用两个指针来枚举所需子序列,他比一般用for循环的枚举更为高效和便捷,他的效率体现在,我们一旦发现子区间符合题意后,接下来的操作就是有关于如何推进区间端点,换句话说,凡是用尺取法的问题,就是与区间端点取舍的相关问题

整个尺取法基本上分为四步
第一步:初始化左右端点
第二步:不断扩大右端点,直到首先满足题意
第三步:满足题意后,终止,更新结果
第四步:扩大左端点,收缩区间,回到第二步

这块借用了大神的图,侵删
在这里插入图片描述
分析:首先我们将两个指针都定为左端点,然后向右扩大右端点,知道10被染色,这个区间就满足题意了,总和为24,然后收缩左端点直到只有10,在这个过程中 , 我们贪心求出最小长度就是2,之后右指针向右扩张,在收缩,每次贪心求出长度一一比较即可

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1e5 + 100;
int a[N];
int main()
{
	int t = 0;
	cin >> t;
	
	while (t --)
	{
		memset (a , 0 ,sizeof a);
	    int n , s;
	    int l = 0 ,r = 0;
	    int ans = 0x3f3f3f;
	    cin >> n >> s;
	    for (int i=1; i<=n; i ++) cin >> a[i];
	    
	    int sum = 0; 
	    while (r <= n && l <= r)
	    {
	    	if (sum >= s) //这里用到了两次if,便于排查
	    	{
	    		ans = min (ans , r - l + 1);
	    		sum -= a[l];
	    		l ++ ;
			}
			
			if (sum < s)
			{
				r ++ ;
				sum += a[r];
			}
		}
	    
	    if (ans == 0x3f3f3f) cout << 0 << endl; //我没有粘贴完题,如果没有找到符合题意的子序列,就输出0
	    else cout << ans << endl;
		
	}
	
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值