Poj 2566 Bound Found(尺取法)

37 篇文章 0 订阅
21 篇文章 0 订阅

题目地址:http://poj.org/problem?id=2566

思路:选择一区间使得其和的绝对值最接近t。

(1)当序列a[1...n]元素单调时,设置两指针:l、r。设当前数的和为sum,当sum大于t时,sum-=a[l];当sum小于t时,sum+=a[r]。则依次遍历可求出最接近t的值。

(2)由于该序列中元素可正可负,不可直接使用尺取法,需将其做适当转化:设sum[i]为该序列1---i的前缀和,则区间[l,r]的和可变为前缀和相减。但由于负数的存在,前缀和并不一定单调,此时需记录前缀和sum[i]的位置i,并将前缀和按从小到大排序,此时序列单调(由于abs(sum[r]-sum[l])==abs(sum[l]-sum[r]),故排序不影响结果)。此时可设置两指针l、r,当l<=r&&r<=n时,计算当前区间和,并更新答案(当当前区间和小于t时,右指针加一(区间和增加),区间和大于t时,左指针加一(区间和减小))。

(3)由于区间不能为空,当l==r时r++;为方便计算和比较1---i的区间和,加入元素sum[0]=0,排序时将其一并排序(sum[i]-sum[0]即为1---i的区间和);由于区间[l,r]的和为sum[r]-sum[l-1]则最后答案左端点需加一(因求区间时按照sum[r]-sum[l])。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debu
using namespace std;
const int maxn=1e5+50;
const int INF=0x3f3f3f3f;
struct Node
{
    int id,tot;
};
Node a[maxn];
int n,q,ans,ansl,ansr;
int cmp(Node a,Node b)
{
    if(a.tot==b.tot) return a.id<b.id;
    else return a.tot<b.tot;
}
int main()
{
#ifdef debug
    freopen("in.in","r",stdin);
#endif // debug
    while(scanf("%d%d",&n,&q)!=EOF&&(n+q))
    {
        a[0].id=0,a[0].tot=0;
        for(int i=1; i<=n; i++)
        {
            int x;
            scanf("%d",&x);
            a[i].id=i;
            a[i].tot=a[i-1].tot+x;
        }
        sort(a,a+n+1,cmp);
        for(int i=0; i<q; i++)
        {
            int t;
            scanf("%d",&t);
            int l=0,r=1,minx=INF;
            while(l<=r&&r<=n)
            {
                int tmp=a[r].tot-a[l].tot;
                if(abs(tmp-t)<minx)
                {
                    minx=abs(tmp-t);
                    ans=tmp;
                    ansl=a[l].id;
                    ansr=a[r].id;
                }
                if(tmp<t) r++;
                else if(tmp>t) l++;
                else break;
                if(l==r) r++;
            }
            if(ansl>ansr) swap(ansl,ansr);
            printf("%d %d %d\n",ans,ansl+1,ansr);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值