尺取法 poj3061

尺取法:就是两个指针表示区间[l,r]的开始与结束然后根据题目来将端点移动,是一种十分有效的做法。适合连续区间的问题

1 poj3061

  给定长度为n的数列整数a0,a1,a2,a3 ..... an-1以及整数S。求出和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。

方法1;暴力:O(n^3枚举)

方法2:通过预先计算sum[i],那么子序列的和就可以在O(1)内找到

注意这题是positive integer,那么sum肯定是递增的,对于每个位置,通过二分搜索找到S-sum[i]<sum[k]的最小k,O(nlogn)

方法3:尺取法:我们若有a[s]+...a[t-1]>S

分析:我们知道连续子序列的和可以在输入的时候获取sum[i],那么i+1到j的连续序列和就可以用sum[j]-sum[i]获得了

主要思想为:当a1,  a2  , a3 满足和>=S,得到一个区间长度3,那么去掉开头a1,   剩下 a2,a3,判断是否满足>=S,如果满足,那么区间长度更新,如果不满足,那么尾部向后拓展,判断a2,a3,a4是否满足条件。重复这样的操作。
个人对尺取法的理解:当一个区间满足条件时,那么去掉区间开头第一个数,得到新区间,判断新区间是否满足条件,如果不满足条件,那么区间末尾向后扩展,直到满足条件为之,这样就得到了许多满足条件的区间,再根据题意要求什么,就可以在这些区间中进行选择,比如区间最长,区间最短什么的。这样跑一遍下来,时间复杂度为O(n)。
<span style="font-size: 14px;">#include <iostream>
#include <cstdio>
#include <iostream>
using namespace std;	
const int maxn=100005;
int a[maxn];
int sum[maxn];
int main(int argc, char const *argv[])
{
	int t,n,s,left,right;
	cin>>t;
	while(t--){
		sum[0]=0;
		cin>>n>>s;
		int ans=n+1;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			sum[i]=sum[i-1]+a[i];
		}
		for(left=0,right=1;left<n;left++){
			while(right<=n&&sum[right]-sum[left]<s){
				right++;
			}//the sum of left+1 to right
			if(right==n+1) break;
			if(right-left<ans) ans=right-left;
		}
		if(ans==n+1) cout<<"0"<<endl;
		else cout<<ans<<endl;
	}

	return 0;
}</span><span style="font-size: 16px;">
</span>



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值