Bound Found POJ

来源:互联网 发布:东莞网站关键字优化 编辑:程序博客网 时间:2024/06/14 13:57

Bound Found

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 的 序列 ,然后 给

你 一个 t 值,让你 求的 一个 连续的 子序列,使得 该序列的 和 的

绝对值,最为接近 t 值,然后 输出 满足 条件的 序列的 和 的绝对值 ,
和 该序列的 左右 边界 下标 。题目的意思很简单,而且 这道题就
是 根据 尺取法 的 思想来写的 , 以前 的 尺取法 的类型题 中 while、循环中的 判断条件 往往是一个 定值 ,而这道题中的 是一个 不断 改变的值 ,每一次 更新为 最优解 ,从而充当 判断条件,
这个 题 我用了一个 pair《int, int》sum[], 这个 数组 是用来 存储 前 I 个 数的 和 ,和 对应的 下标 i ;【思路】

……前缀和比较神奇的想法。一般来说,我们必须要保证数列单调性,才能使用尺取法。

预处理出前i个数的前缀和,和编号i一起放入pair中,然而根据前缀和大小进行排序(从小到大排序(sort 函数的 默认排序方式))。由于abs(sum[i]-sum[j])=abs(sum[j]-sum[i]),可以忽视数列前缀和的前后关系。此时,sum[r]-sum[l]有单调性。

因此我们可以先比较当前sum[r]-sum[l]与t的差,并更新答案。

如果当前sum[r]-sum[l]

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef pair<int, int> p;p sum[100010];int main(){    int n, m, num;    while(scanf("%d%d", &n, &m) && n+m)    {        sum[0] = make_pair(0, 0);// 读入 一组数据也可以 用 sum[0] = p(0, 0);        for(int i = 1; i <= n; i++)// 先用 pair 存起来        {            scanf("%d", &num);            sum[i] = make_pair(sum[i-1].first + num, i);        }        sort(sum, sum+1+n);// 从小到大 排序 这里 要注意 排序的 范围 是 sum -> sum+1+n  不要 写成 sum+1->sum+1+n  如果你要是 写成 后者的话,那么 sum[0].first  <=  sum[1].first  就不一定成立啦 因为  sum[1].first 可能 是 负值, 那么 在下面 尺取法 的 方法中  temp 可能会小于零 啦 这样程序就会出错啦;        int t;        int L, R, s, e, temp, dif, ans;        while(m--)        {            scanf("%d", &t);            s = 0;// 这里 之所以 s = 0, e = 1;是为了 防止 s = e 出现 空区间            e = 1;            dif = INT_MAX;            while(e <= n)            {                temp = sum[e].first - sum[s].first;                if(abs(temp-t) < dif)                {                    dif = abs(temp - t);                    L = sum[s].second;                    R = sum[e].second;                    ans = temp;                }                if(temp < t) e++;// temp 还可能 变大一点                else if(temp > t) s++;// temp  还可能 变小一点                 else break;// s = e 最优解 直接跳出循环                if(s == e) e++;// 防止出现空区间            }            if(L > R) swap(L, R);// 由于 排序的 原因  L R 是 乱序 负值的            printf("%d %d %d\n", ans, L+1, R);        }    }    return 0;}
原创粉丝点击