POJ 2566

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83548434

 这道题仍然是一个尺取法 尺取法 需要整个数列具有单调性 (开始我一直以为单调性是单调递增或递减,然而并不是)

单调性就是 比如 区间取和 我在右边界向右延伸的过程中 整个区间和是不断增大的 不会变小 不然右侧就不会延伸 反而右边会向回收缩,这样的话就会造成一种很混乱的局面。

那么我们来看题目

本体题意:

一共N个数 给你K个数字 每个数字大小为 T 求一个区间使其区间和最接近T 

输入 N K 然后输入 N个数字,最后输入K个 T

输出 区间和 区间左边界 右边界

(多组输入,n==k==0时结束)

因为这道题目 给的数字可能是  负数   如果还按照老的方法去算 可能会出现 r 向回收缩,l 向左延伸的现象,所以为了避免这种情况,我们可以引入前缀和,然后排序一下,这样不就可以保证 R 在向右的过程中 整个区间和是一直在增大的,L 收缩的过程中整个区间和是一直在减小的 ,成功实现尺取法

下方是AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 1e6+5;
const int inf = 0x3f3f3f3f;
int fabs(long long int x)
{
	return x<0?-x:x;
}
struct node
{
	long long int id,v;
}num[maxn];
bool cmp(node a,node b)
{
	return a.v<b.v;
}
int n,t,k;
int l,r;
long long int a[maxn];
int main()
{
	while(cin>>n>>k&&n+k!=0)
        {
	for(int i=0;i<=n;i++)
	num[i].v=0,num[i].id=i;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		num[i].v=num[i-1].v+a[i];
	}
	sort(num,num+n+1,cmp);
	while(k--)
	{
		cin>>t;
		l=0,r=1;
		long long int ll,rr,minn=inf,ans;
		while(l<=n&&r<=n&&minn!=0)
		{
			long long int temp = num[r].v-num[l].v;
			if(minn>fabs(t-temp))
			{
			    minn=fabs(t-temp);	
			    ll=num[l].id;
			    rr=num[r].id;
			    ans=temp;
			}
			if(temp > t)
			l++;
			else if(temp < t)
			r++;
		  	else break;
		  	if(l==r)r++;
		}
		if(ll>rr) swap(ll,rr);
		cout<<ans<<' '<<ll+1<<' '<<rr<<endl;
	}
        }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/83548434