POJ - 2566 Bound Found

题意:询问一个静态序列的连续区间和绝对值最接近t的下标。

分析:由于询问的是绝对值,可以用前缀和相减得到区间和,并且和位置前后没有关系。于是把记录下标信息以后把

前缀和排序枚举大的前缀pj,pj-pi ≈ t,满足条件的:有pj-t的plower_bound以及plower_bound-1

而pj-t也是单调的,再用一个下标i去维护就好。

/*********************************************************
*            ------------------                          *
*   author AbyssalFish                                   *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<numeric>
using namespace std;

const int maxn = 1e5+1;

int t, n, k;

typedef pair<int,int> node;
#define val first
#define idx second
node a[maxn];

int best, lb, ub;

void update(int i,int j)
{
    if(abs(a[j].val - a[i].val - t) < abs(best-t)){
        best = a[j].val - a[i].val;
        lb = a[i].idx; ub = a[j].idx;
    }
}

void solve()
{

    a[0].val = a[0].idx = 0; //空前缀是必要的
    for(int i = 1; i <= n; i++) {
        a[i].val += a[i-1].val;
        a[i].idx = i;
    }
    sort(a,a+n+1);
    while(k--){
        scanf("%d",&t);
        best = a[1].val-a[0].val, lb = a[1].idx, ub = a[0].idx; //(lb,ub]
        for(int i = 0, j = 1; j <= n; j++){
            while(i < j && a[j].val - a[i].val > t) { //[i,j]
                i++;
            }
            if(i) update(i-1,j);
            if(i < j) update(i,j);
        }
        if(ub < lb) swap(ub, lb);
        printf("%d %d %d\n", best, lb+1, ub);
    }

}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif

    while(scanf("%d%d",&n,&k),n){
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i].val);
        }
        solve();
    }
    return 0;
}

 

posted @ 2015-11-22 18:35  陈瑞宇  阅读(258)  评论(0编辑  收藏  举报