Loading

POJ-2566 Bound Found

Bound Found

给出一个数组,要找到一个连续子序列的和的绝对值最接近给出的k

尺取

这个尺取非常难想到

我们使用尺取的时候讲究的是固定了左端,然后右端一直往右滑动,如果滑动到一个不符合条件的情况,那么后面的情况都不符合。但是由于该数组存在负数的情况,所以显然不符合尺取的条件,考虑排序

直接排序显然做不了,我们考虑对每个位置求一个前缀和,然后带着index进行排序,这样就可以做到滑动的时候,区间的差是不断增大的(这里的区间[l,r]的index并不单调,所以有点反直觉,有点难想到)

做这题有感悟:

  1. 尺取真的得小心边界

  2. 在考虑前缀和的时候,一定要考虑一开始的sum[0],这里也是要加入一起排序中

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;

struct node
{
    ll val, id;
    node(){}
    node(ll _val, ll _id){val = _val; id = _id;}
}num[maxn];

bool cmp(const node& a, const node& b)
{
    return a.val < b.val;
}

ll sabs(ll a)
{
    return a > 0 ? a : -a;
}

int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF && (n | m))
    {
        num[0].val = num[0].id = 0;
        for(int i=1; i<=n; i++)
        {
            ll x;
            scanf("%lld", &x);
            x += num[i-1].val;
            num[i] = node(x, i);
        }
        sort(num, num + n + 1, cmp);
        
        while(m--)
        {
            ll k;
            scanf("%lld", &k);
            int l = 0, r = 1, lans = 0, rans = 0;
            ll minn = 1e17 + 10, ans = 0;
            while(r <= n)
            {
                ll now = num[r].val - num[l].val;
                ll temp = abs(now - k);
                if(temp < minn)
                {
                    lans = num[r].id;
                    rans = num[l].id;
                    minn = temp;
                    ans = now;
                }

                if(now == k) break;
                if(now > k) l++;
                else r++;
                if(l == r) r++;
            }
            if(lans > rans) swap(lans, rans);
            printf("%lld %d %d\n", ans, lans + 1, rans);
        }
    }
    return 0;
}
posted @ 2022-05-13 01:21  dgsvygd  阅读(38)  评论(0编辑  收藏  举报