poj 2566 Bound Found 尺取法 变形

Bound Found
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 2277   Accepted: 703   Special Judge

Description

Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronautic and Space Administration (that must be going through a defiant phase: "But I want to use feet, not meters!"). Each signal seems to come in two parts: a sequence of n integer values and a non-negative integer t. We'll not go into details, but researchers found out that a signal encodes two integer values. These can be found as the lower and upper bound of a subrange of the sequence whose absolute value of its sum is closest to t. 

You are given the sequence of n integers and the non-negative target t. You are to find a non-empty range of the sequence (i.e. a continuous subsequence) and output its lower index l and its upper index u. The absolute value of the sum of the values of the sequence from the l-th to the u-th element (inclusive) must be at least as close to t as the absolute value of the sum of any other non-empty range.

Input

The input file contains several test cases. Each test case starts with two numbers n and k. Input is terminated by n=k=0. Otherwise, 1<=n<=100000 and there follow n integers with absolute values <=10000 which constitute the sequence. Then follow k queries for this sequence. Each query is a target t with 0<=t<=1000000000.

Output

For each query output 3 numbers on a line: some closest absolute sum and the lower and upper indices of some range where this absolute sum is achieved. Possible indices start with 1 and go up to n.

Sample Input

5 1
-10 -5 0 5 10
3
10 2
-9 8 -7 6 -5 4 -3 2 -1 0
5 11
15 2
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
15 100
0 0

Sample Output

5 4 4
5 2 8
9 1 1
15 1 15
15 1 15

Source

题意:给你n个数字,这些数字可正可负,再给你个数字t,求在这个数列中一个连续的子序列,和的绝对值与t相差最小
 
错因分析:刚开始看到这道题目觉得很变态,尺取法怎么可能做得出来,这些数字是可正可负的,,后来看了题解,才恍然大悟,正因为是可正可负所以不能直接用尺取法去解题(尺取法必须是找到单调性),需要进行转化,找到单调性,但是a[i]数组是不能改变的,因为要求连续,那么就自然想到对a[i]求前缀和
 
先贴上别人好的代码,核心思想:对sum进行从小到大的排序,注意需要加入<0,0>这点(为了求得单独的sum,就是从第一个节点到sum[i]对应的i节点),然后尺取法设置左右两个端点,直接在sum数组上进行尺取法,需要注意的是对两个端点移动的判断,假设得出的int temp=p[r].first - p[l].first<k,说明temp偏小,那么r端点右移,否则>k的话,说明temp偏大,需要l端点右移,但是需要注意不能出现l==r的情况,因为序列不能为空,l==r,则序列为空;还有一点很重要的是因为求得是和的绝对值,即|sum[j]-sum[i]|,那么只需要对sum数组进行从小到大排序,用大的减去小的就可以了(这也是去绝对值的体现)
#include<cstdio>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include<map>
#include <algorithm>
#include <set>
using namespace std;
#define MM(a) memset(a,0,sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
const int mod = 1000000007;
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
pair<int, int > p[100005];
int n, m, k;
void solve(int k)
{
	int l = 0, r = 1, al, ar, av, minn = inf;
	  while (l<=n&&r<=n&&minn!=0)
		{
			int temp=p[r].first - p[l].first;
			if (abs(temp - k) < minn)
			{
				minn = abs(temp - k);
				ar = p[r].second;
				al = p[l].second;
				av = temp;
			}
			if (temp> k)
				l++;
			else if (temp < k)
				r++;
			else
				break;
			if (r == l)
				r++;
	   }
    if(al>ar)
        swap(al,ar);//因为al和ar大小没有必然关系()取绝对值,所以//要交换
	printf("%d %d %d\n", av, al+1, ar);
}
int main()
{
	while (~scanf("%d %d", &n, &m))
	{
		if (!n&&!m) return 0;
		p[0] = make_pair(0, 0);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &p[i].first);
			p[i].first += p[i - 1].first;
			p[i].second = i;
		}
		sort(p, p + n + 1);
		while (m--)
		{
			scanf("%d", &k);
			solve(k);
		}
	}
	return 0;
}

  下面是自己的wa代码

     好好找茬

#include<cstdio>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include<map>
#include <algorithm>
#include <set>
using namespace std;
#define MM(a) memset(a,0,sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
const int mod = 1000000007;
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
pair<int, int > p[100005];
int n, m, k;
void solve(int k)
{
	int l = 0, r = 1, al, ar, av, minn = inf;
	  while (l<=n&&r<=n)
		{
			int temp = p[r].first - p[l].first;
			if (abs(temp - k) < minn)
			{
				minn = abs(temp - k);
				ar = p[r].second;
				al = p[l].second;
				av = temp;
			}
			if (temp > k)
				l++;
			else if (temp < k)
				r++;
			else
				break;
			if (r == l)
				r++;
	}
	printf("%d %d %d\n", av, al+1, ar);
}
int main()
{
	while (~scanf("%d %d", &n, &m))
	{
		if (!n&&!m) return 0;
		p[0] = make_pair(0, 0);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &p[i].first);
			p[i].first += p[i - 1].first;
			p[i].second = i;
		}
		sort(p + 1, p + n + 1);
		while (m--)
		{
			scanf("%d", &k);
			solve(k);
		}
	}
	return 0;
}

  

posted @ 2016-01-14 12:10  快点说我帅  阅读(1325)  评论(0编辑  收藏  举报