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个整数,然后是k次查询,每次都查询一个绝对值和接近t的子序列,并且输出所求得的和与上、下界
分析:
这一道题很像是尺取法的板子,但是仔细去想,尺取法是应用于单调递增的前序和的序列才行,什么意思呢?
1,2,-3,4 像这个序列,它的前序和是1 ,3,0,4 这个就不是递增的序列和;
但是像下面这个:
-3 ,1,2,3 它的前序和是-3,-2,0,3 ,这个就是一个递增的序列和;
那么依据这个原则,我们需要去改变这个所给的序列,怎么去把这个序列变成一个递增的
我们可以这样去处理,举个栗子:
-9 8 -7 6 -5 4 -3 2 -1 0
对于上面这个样例(也就是题目中的第二个样例),它的前序和是:
-9,-1,-8,-2,-7,-3,-6,-4,-5,-5
下标 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
然后将这些值按照值从小到大进行排序:
-9,-8,-7,-6,-5,-5,-4,-3,-2,-1
下标:1,3,5, 7, 9,10,8, 6, 4, 2
通过前序和(也叫前缀和吧),就能够求出任意区间的和,比如sum=p[i]-p[j],这就是区间[j+1,i]的区间和,处理到这里就可以看出,剩下的就是用尺取法了,只需要每次找到合适的区间和-t,将其值最小化就可以了
因为是求得的是绝对值,因此不需要在乎谁的下标大,谁的下标小,只需要在后面进行处理一下就好了
下面是AC的代码:
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
//#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Abs(x) ((x)>=0?(x):-(x))
int n,k;
ll t;
pair<int,int>p[N];
void solve(){
int i=0,j=1;
int pare=INF;
ll ans=LINF,sum=0;
int l,r;
while(j<=n&&i<=n){
sum=p[j].first-p[i].first;
if(Abs(sum-t)<pare){
ans=sum;
pare=Abs(sum-t);
r=p[j].second;
l=p[i].second;
}
if(sum<t) j++;
else if(sum>t) i++;
else break;
if(i==j) j++;
}
if(r<=l) swap(l,r);
printf("%lld %d %d\n",ans,l+1,r);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
while(scanf("%d%d",&n,&k)!=EOF,n+k){
int tt=0;
p[0]=make_pair(0,0);
rep(i,1,n){int u;
scanf("%d",&u);
tt+=u;
p[i]=make_pair(tt,i);
}
// cout<<p[1].first<<" "<<p[1].second<<endl;
sort(p,p+n+1);
while(k--){
scanf("%lld",&t);
solve();
}
}
return 0;
}