poj

来源:互联网 发布:stc单片机系统分析 编辑:程序博客网 时间:2024/06/16 12:11

Bound Found

Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 4861 Accepted: 1558 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

Ulm Local 2001

题意: 给你n,k给你n个可正可负的数列,然后给你k次询问,让你求出在序列中一段连续的序列和的绝对值最接近询问值,然后输出最接近的数,以及区间范围

分析: 这个就有点意思了,一开始都是正数,直接尺取来进行查找就行,但是这个可正可负,就有点难搞了,不能用常规的思路了,因为要想用尺取的前提是一个有序的,可判定的序列,由于题目说的是连续序列和的绝对值,也就是说我们只需要知道两个端点即可,不用管谁前谁后,看了dalao 的解题发现了一种比较有思维的方法,就是利用前缀和来进行判定,我们来枚举前缀和的两个端点,从而可以找到一个最接近询问值的数,我们在存前缀和的同时还得把相应的坐标给存上,这里可以建个结构体,因为一会还要对前缀和进行排序,于是这里直接利用stl里面的pair来进行存储即可(因为pair自带比较,先对first升序,如果一样的话,再对second升序),然后我们设置一个compare来进行比较选出和询问值差别最小的,进行尺取即可
注意: (1) 要在pair第一个虚加一个(0,0),因为考虑后面可能是前几项的和,如果去掉的话取不到这个值;
(2) 自己可以模拟一下为什么最后在左端点加一(这个前缀和其实是包括这一位之前的和,减去的话其实是算的(ansL+1,ansR)

参考代码

#include <cstdio>#include <algorithm>#include <iostream>#define fi first#define se secondusing namespace std;const int N = 1e5 + 10;pair<int,int> preSum[N];int main(){    ios_base::sync_with_stdio(0);    int n,m;    while(cin>>n>>m,n+m){        preSum[0] = make_pair(0,0);        for(int i = 1;i <= n;i++){            cin>>preSum[i].fi;            preSum[i].se = i;            preSum[i].fi += preSum[i-1].fi;        }        sort(preSum,preSum+n+1);        while(m--){            int x;cin>>x;            int l = 0,r = 1,compare = 1<<30,ans,ansL,ansR;            while(compare){                int t = preSum[r].fi - preSum[l].fi;                if(abs(t-x) < compare){                    ans = t;                    ansL = preSum[l].se;                    ansR = preSum[r].se;                    compare = abs(t - x);                }                if(t < x && r < n) r++;                else if (l < n)l++;                if(l == r && r < n) r++;                if(r == n && l == n) break; //这里的break要控制好            }            if(ansL > ansR) swap(ansL,ansR);            ansL++;            cout<<ans <<' '<<ansL<<' '<<ansR<<endl;        }    }    return 0;}
  • 如有错误或遗漏,请私聊下UP,thx