//poj2566//Bound Found//尺取法+前缀处理//超级好题

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

解题思路:
本来以为这是一道模板题,后来发现对于我这种蒟蒻来说还是有点难度的,无论是整体思路,还是细节处理。
首先说思路,想用尺取法解决问题,序列必须是单调的,否则无法推进端点。但是这道题中肯定不能打乱输入序列的顺序,所以必须找到一个能排序、不会影响输入序列顺序、能算出某一区间总和的序列。这个序列就是前n项的和。太妙了。我真的想不到这种操作。
还有几个需要注意的细节,一个是将pre排序的时候要从pre[0]排到pre[n],我一直是从pre[1]开始排,所以一直错。现在也还没太想明白为什么从pre[0]开始……
还有一点是应该输出ansl+1,因为left是被减掉的数,而不是第一个加进去的数。
还有一点是当left=right的时候,要改变left或者right的值,否则区间总和不存在。

今天又想了想,试了几组数据,好像有点明白为什么要从pre[0]排到pre[n]了。首先pre[0]存在的意义是pre[n]-pre[0]能得到1-n这个区间的和,所以pre[0]的地位和pre[n]是一样的,只不过pre[0]的值已经提前设定好了。虽然pre[0]一定等于0,但是pre里面可能有负数或者正数,所以pre[0]的排序后的位置其实不能确定。如果不把pre[0]加入排序过程,无论下标怎么推进,都得不到1-n区间的和,只能是2-n。

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

struct node
{
    int p;
    int sum;
}pre[100000];

int num[100000];

bool cmp(node x,node y)
{
    return x.sum<y.sum;
}

int main()
{
    int n,k,i,t;
    while(1)
    {
        scanf("%d%d",&n,&k);
        if(n==0&&k==0)
            break;
        pre[0].p=0;
        pre[0].sum=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            pre[i].p=i;
            pre[i].sum=pre[i-1].sum+num[i];
        }
        sort(pre,pre+n+1,cmp);
        while(k--)
        {
            scanf("%d",&t);
            int left=0,right=1,all,ansl,ansr,ans,min=0x3f3f3f3f;
            while(left<=n&&right<=n)
            {
                all=pre[right].sum-pre[left].sum;
                if(abs(all-t)<min)
                {
                    min=abs(abs(all)-t);
                    ans=all;
                    ansl=pre[right].p<pre[left].p?pre[right].p+1:pre[left].p+1;
                    ansr=pre[right].p>pre[left].p?pre[right].p:pre[left].p;
                }
                if(all<t)
                    right++;
                else if(all>t)
                    left++;
                else
                    break;
                if(left==right)
                    right++;
            }
            printf("%d %d %d\n",ans,ansl,ansr);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lydia_ke/article/details/79418730