题目链接:http://poj.org/problem?id=2566
Bound Found
Time Limit: 5000MS | Memory Limit: 65536K | |||
Total Submissions: 4727 | Accepted: 1502 | 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.
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
题目大意:
给出一个整数列,求一段子序列之和最接近所给出的t。输出该段子序列之和及左右端点。
题目分析:由于给出的整数列不是非负的,不能直接采用尺取法。
一般来说,我们必须要保证数列单调性,才能使用尺取法。
预处理出前i个数的前缀和,和编号i一起放入pair中,然而根据前缀和大小进行排序。
由于abs(sum[i]-sum[j])=abs(sum[j]-sum[i]),可以忽视数列前缀和的前后关系。此时,sum[r]-sum[l]有单调性。
因此我们可以先比较当前sum[r]-sum[l]与t的差,并更新答案。
如果当前sum[r]-sum[l]<t,说明和还可以更大,r++。
同理,如果sum[r]-sum[l]>t,说明和还可以更小,l++。
如果sum[r]-sum[l]=t,必定是最小答案。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
typedef long long LL;
const int N=100000+999;
const int inf=0x3f3f3f3f;
pair<int,int> a[N];
int n,m;
void sky(int k)
{
int l=0,r=1,mi=inf,res;
int al,ar;
while(r<=n&&mi)
{
int x=a[r].first - a[l].first;
if(abs(x-k)<mi)
{
res=x;
mi=abs(x-k);//要一直更新与k的差
al=a[l].second;
ar=a[r].second;
}
if(x<k) r++;//说明和还可以更大
if(x>k) l++;//相反
if(l==r) r++; //区间不能为空
}
if(al>ar) swap(al,ar); //乱序 变成 有序
printf("%d %d %d\n",res,al+1,ar); //+1由于把0也参与排序
}
int main()
{
while(scanf("%d%d",&n,&m)&&n)
{
a[0]=make_pair(0,0);
int sum=0,x;
for(int i=1; i<=n; i++)
{
scanf("%d",&x);
sum=sum+x;
a[i]=make_pair(sum,i);//将前缀和与下标联系
}
sort(a,a+n+1);//由于将0也排序所以从(0,n+1)排序
int k;
while(m--)
{
scanf("%d",&k);
sky(k);
}
}
return 0;
}