Bound Found POJ - 2566(尺取)

2 篇文章 0 订阅
这是一道编程题,题目要求找到一个整数序列中子序列的和,使其绝对值最接近给定的目标值t。通过计算序列的前缀和并排序,可以使用尺取法找到满足条件的子序列。解题思路包括计算前缀和、排序和应用尺取策略来找到最接近目标的和及其对应子序列的边界。
摘要由CSDN通过智能技术生成

题目来源:Bound Found

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

题意

给定一个数列,求某个子序列的和的绝对值最接近给定的t,输出这个序列的和的绝对值,左右端点

思路

由于要求某个子序列的和的绝对值接近t,所以求出前缀和后可以进行排序,排序后任意两者的差值不影响(和的绝对值)这个结果。这样满足单调性,可以尺取求出符合题意的区间。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <utility>
using namespace std;
int n, k;
long long a[100005];
pair<long long, int>sum[100005];
inline long long Abs(long long x)
{
    return x > 0 ? x : -x;
}
int main()
{
    while (true)
    {
        scanf("%lld%lld", &n, &k);
        if (n == 0 && k == 0)
            break;
        sum[0] = make_pair(0, 0);
        for (int i = 1; i <= n; ++i)
        {
            scanf("%lld", a + i);
            if (i == 1)
                sum[i].first = a[i];
            else
                sum[i].first = sum[i - 1].first + a[i];
            sum[i].second = i;
        }
        sort(sum, sum + 1 + n);

        while (k--)
        {
            long long t;
            scanf("%lld", &t);
            int l = 0, r = 1;
            long long min_delta = 99999999999;
            long long ls, rs, ans;
            while (r <= n && min_delta)
            {
                long long delta = Abs(sum[r].first - sum[l].first);
                if (Abs(delta - t) < min_delta)
                {
                    min_delta = Abs(delta - t);
                    ans = delta;
                    ls = sum[l].second;
                    rs = sum[r].second;
                }
                if (delta > t)
                    l++;
                if (delta < t)
                    r++;

                if (l == r)
                    r++;
            }
            if (ls > rs)
                swap(ls, rs);

            printf("%lld %lld %lld\n", ans, ls + 1, rs);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值