Time Limit: 5000MS | Memory Limit: 65536KB | 64bit IO Format: %lld & %llu |
Description
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
Output
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个数,做k次查询,求在数列中存在的区间[ left,right ],使得区间中数的和的绝对值与t最接近。
题解:基本思路:统计出前缀和,然后找到两段前缀和差的绝对值最接近t。 我们用尺取法,因为前缀和是无序,需要先将前缀和从小到大排好序,这样才能用尺取法推进查找记录最小值。 在建立前缀和时,建立编号记录下标,通过编号还原位置。
在处理前缀和排序时的有很强的技巧性。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cmath>
using namespace std;
const int N = 100110;
const int inf = INT_MAX;
int v[N];
struct node
{
int id, sum;
} p[N];
int cmp(node a,node b)
{
return a.sum<b.sum;
}
int main()
{
int n, q;
while(scanf("%d %d", &n, &q),n||q)
{
for(int i=1; i<=n; i++)
{
scanf("%d", &v[i]);
}
int tmp;
p[0].sum=0;
p[0].id=0;
for(int i=1; i<=n; i++)
{
p[i].sum=p[i-1].sum+v[i];
p[i].id=i;
}
sort(p,p+n+1,cmp);
while(q--)
{
scanf("%d", &tmp);
int l=0, r=1, ans=inf, ansl=1, ansr=1;
while(r<=n)
{
int k1=min(p[l].id,p[r].id), k2=max(p[l].id,p[r].id);
int num=abs(p[r].sum-p[l].sum);
if(abs(ans-tmp)>=abs(num-tmp))
{
ansl=k1+1, ansr=k2;
ans=num;
}
if(num>tmp)
{
l++;
}
else if(num<tmp)
{
r++;
}
else if(num==tmp)
{
break;
}
if(r==l)
{
r++;
}
}
printf("%d %d %d\n",ans, ansl, ansr);
}
}
return 0;
}