Bound Found POJ - 2566 (尺取好题)

Posted alexlins

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bound Found POJ - 2566 (尺取好题)相关的知识,希望对你有一定的参考价值。

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

题意:从数列中找出连续序列,使得和的绝对值与目标数之差最小,对于每次查询,输出三个整数sum,l,r,分别表示其绝对值与目标数之差最小的连续序列值与此连续序列的左右端点
   如果有多种解,可输出其任意一种。
思路:对于连续区间和,我们要想到前缀和,所以开一个pair(int,int) 分别记录前缀和的值和此时的位置。
   然后用 sum[r] - sum[l] 算出区间和。
   如果区间和sum[r] - sum[l] > m 比目标值要大,那么尾部就要推进 L++
   如果区间和sum[r] - sum[l] < m 比目标值要小,那么头部就要推进 R++
   sum[r] - sum[l] = m 的时候break出来就可以了。还有注意要防止出现空区间(代码中已注释)

代码

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%d",&a)
#define pr(a) printf("%d",a);
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e9 + 7;
const int Maxn = 1e6+9;
const double pi = acos(-1.0);
const double eps = 1e-8;

int a[Maxn], n, k, m;
pii sum[Maxn];

int main() {
    while (~scanf("%d%d", &n, &k)) {
        if (n == 0 && k == 0)break;
        sum[0] = make_pair(0, 0);
        FOR(i, 1, n) {
            sc(a[i]);
            sum[i] = make_pair(sum[i - 1].first + a[i], i); //用pair将前缀和存起来
        }

        sort(sum, sum + 1 + n);
        while (k--) {
            sc(m);
            int l = 0, r = 1, ans, dis=INF; //l=0, r=1 防止 l=r的时候出现空区间
            int ansl, ansr;
            while (r <= n) {
                int t = sum[r].first - sum[l].first;//两点之间的区间和
              //  cout << sum[r].first << "——" << sum[l].first << endl;
             //   cout << t << endl;
                if (abs(t - m) < dis) {
                    dis = abs(t - m);
                    ansl = sum[l].second;
                    ansr = sum[r].second;
                    ans = t;
                   // cout << ansl << "————" << ansr << endl;
                }
                if (t < m) r++;//区间可以变大
                else if (t > m) l++;//区间可以变小一点
                else break;
                if (l == r) r++; // 防止出现空区间
            }
            if (ansl > ansr) swap(ansl, ansr);
            printf("%d %d %d
", ans, ansl+1, ansr);
        }
    }
    return 0;
}

  

以上是关于Bound Found POJ - 2566 (尺取好题)的主要内容,如果未能解决你的问题,请参考以下文章

POJ2566-Bound Found (尺取法)

Bound Found [POJ2566] [尺取法]

Greedy:Bound Found(POJ 2566)

POJ 2566:Bound Found(Two pointers)

挑战程序设计竞赛3.2习题:Bound Found POJ - 2566

POJ - 2566 Bound Found(尺取法+前缀和)