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\n", ans, ansl+1, ansr);
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/AlexLINS/p/12690204.html

时间: 2024-11-02 11:45:40

Bound Found POJ - 2566 (尺取好题)的相关文章

Jessica&#39;s Reading Problem POJ 3320(尺取)

原题 题目链接 题目分析 题目要求一段连续的书页,里面包括了全部知识点,可以考虑尺取,由于知识点的编号无规律,可以考虑用set来记录全部知识点的种数,尺取的过程可以考虑用map来辅助判断区间[s,t]是否包括全部知识点,映射map<知识点编号,个数>,当每种知识点个数至少为1的时候表明[s,t]包含所有知识点. 代码 1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #inclu

挑战程序设计竞赛3.2习题: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

POJ 2566 尺取法(进阶题)

Bound Found Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4297   Accepted: 1351   Special Judge Description Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronautic and Space Administration

POJ 2566(尺取法

自己看了半天并没有看出这题怎么用尺取法(虽然一看就觉得肯定是尺取法..),由于是绝对值,那么在计算的时候头和尾的实际位置并不重要,而应用尺取法这个数列肯定得是单调,那么我们把前缀和处理出来排序就可以直接应用尺取法了 #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<utility> #include<vector> #inc

Greedy:Bound Found(POJ 2566)

   神奇密码 题目大意:就是给你一个数组,要你找出连续的数的绝对值的和最接近t的那一串,并且要找出数组的上界和下界的下标,并显示他们的和 因为这一题的数有正有负,所以必须要先把和求出来,然后排序,然后利用a(s,t)=sum(t)-sum(s)找出目标 1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 5 using namespace std; 6 7 //pair<i

poj 2566 Bound Found (前缀和,尺取法(two pointer))

Bound Found Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 2010   Accepted: 659   Special Judge Description Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronautic and Space Administration

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

题目链接:http://poj.org/problem?id=2566 题意:给定一个序列(n个整数)和一个整数k(m个),求出这个序列的一个子串,使之和的绝对值与k的差最小. 尺取法的题目有两个特性: 1. 所求的序列是一个连续的序列,这样才能将序列抽象成一个头和一个尾来描述. 2. 头尾枚举的序列满足某种单调的性质,这样才能进行尺取的操作. 这个序列是一个随意的序列,不可能直接对其进行操作,先要预处理下,进行前缀和操作,把对应的值和标记放在同一个pair. 然后根据前缀和的值进行排序,这样就

POJ 2566:Bound Found(Two pointers)

[题目链接] http://poj.org/problem?id=2566 [题目大意] 给出一个序列,求一个子段和,使得其绝对值最接近给出值, 输出这个区间的左右端点和区间和. [题解] 因为原序列的前缀和不具有单调性,难以处理, 因此我们对前缀和进行排序,同时保留前缀和的右端点做标识作用, 题目要求区段和的绝对值最接近目标,因此排序不会造成前后顺序变化造成的影响 现在题目转化为在一个有序数列中,求一个数对,使得差值最接近给出数, 利用单调性,可以尺取解决问题. [代码] #include <

Codeforces Round #451 (Div. 2)【A,B,C,D,E】【C题:模拟 D题:尺取+贪心 E题:思维+优先队列维护最值】

特判最后一位即可 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 #define int long long 5 6 signed main(){ 7 int n;cin>>n;int t=n%10; 8 if(t==0) cout<<n; 9 else if(t>5) { 10 cout<<(n+10-t); 11 } 12 else { 13 cout<<(n-t); 14 }