Bound Found POJ - 2566 (尺取+前缀和)

题意 就是给一串序列 在给一个t 求一段区间的加和绝对值与t最小的值与区间左右端点是多少 



思路 这道题一开始不知道如何去做 用尺取法求区间但是因为区间中存在负数没有单调性  没有特殊的特征

若对区间求一下前缀和 就使整个区间有了单调性   由于绝对值情况下 没有前后 所以我们队前缀和后的序列排序

对排序后的前缀和数串进行尺取 若是l和r内的数比t小r++ 比t大就l++ 若相等就break



code:


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf = 100010;

pair<int,int>sum[inf];
int main()
{
	int n,k;
	while(cin>>n>>k,n+k)
	{
		int tem=0;
		sum[0]=make_pair(0,0);
		for(int i=1;i<=n;i++)
		{
			int p;
			scanf("%d",&p);
			tem+=p;
			sum[i]=make_pair(tem,i);
		}
		sort(sum,sum+n+1);
//		for(int i=0;i<=n;i++)
//		cout<<sum[i].first<<" "<<sum[i].second<<endl;
		while(k--)
		{
			int t;
			scanf("%d",&t);
			int al,ar,ami,l=0,r=1,MAX = 2000000000;
			while(r<=n&&MAX)
			{
				int ee = sum[r].first-sum[l].first;
				if(abs(ee-t)<MAX)
				{
					MAX = abs(ee-t);
					ami = abs(ee);
				//	cout<<ami<<" "<<l<<" "<<r<<" 123"<<endl;
					al = sum[l].second;
					ar = sum[r].second;
				}
				if(ee<t)r++;
				else if(ee>t)l++;
				else break;
				if(l==r)r++;
			}
			printf("%d %d %d\n",ami,min(al,ar)+1,max(al,ar));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值