poj2566 Bound Found(尺取法:子串和为非单调序列,模板)

题目大意
给定一组包含n个整数的数列和k个询问,求取一个子串,使得该***连续子串***的***和的绝对值***最接近t

注:暴力求解必定超时

解题思路

  1. 由于要求取一个连续子串的部分和(和为非单调数列,若是单调数列,可不求和,直接算),这让我们想到了记录前缀和sum的方式来在O(1)内求得任意子串的和。
  2. 对于子串问题的处理,为了避免暴力双重循环,我们往往使用尺取法(双指针法),就像是在字符串匹配问题时的那样。当然,其他的方法(如DP)也经常用来处理子串问题,最经典的有最长上升子序列。
  3. 在使用双指针法时,要求序列具有一定的单调性。也正是因为序列具有单调性,才是我们能固定左端点,移动右端点,到达一定情况时,则可以移动左端点,从未有过任何回溯,从而形成节约。
  4. 这里我们显然不能将原序列sort后进行取尺操作,这会丧失原序列的位置信息,不满足子串条件。可借用pair记录位置信息。
  5. 在双指针移动中,可能导致st、en重合,这是需要人为地将en向后移动。当重合时,sum相减为0,相当于不存在数。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#define INF 0x3f3f3f3f
#define MAXN 100005
using namespace std;

typedef pair <int, int> p;
int n, k, t;
int a[MAXN];
p sum[MAXN];

int main()
{
	while(scanf("%d%d", &n, &k), n+k){
		sum[0] = p(0, 0);
		for(int i = 1; i <= n; i++){
			scanf("%d", &a[i]);
			sum[i] = p(sum[i-1].first + a[i], i);
		}
		sort(sum, sum + 1 + n);//从0开始,否则无法记录从a[1]开始的序列
		
		while(k--){
			scanf("%d", &t);
			int st = 0, en = 1, tmp = INF, b, l, u, ans;
			while(en <= n){
				b = sum[en].first - sum[st].first;
				if(abs(t - b) < tmp){
					tmp = abs(t - b);
					ans = b;
					l = sum[st].second;
					u = sum[en].second;
				}
				if(b < t) en++;//此题先处理,再移右端点,且一个个移
				else if(b > t) st++;
				else break;
				if(st == en) en++;//无数字存在的情况
			}
			if(l > u) swap(l, u);
			printf("%d %d %d\n", ans, l + 1, u);//序列中不包含a[l]
		}
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值