POJ-2566 Bound Found(尺取法变形)

来源:互联网 发布:ubuntu selinux设置 编辑:程序博客网 时间:2024/05/16 17:59

题目链接

题意:给出n个整数和k次查询,每次查询给出一个非负整数t,要求找到区间[i,j],使[i,j]内的数之和的绝对值与t的差距最小,每次查询输出和的绝对值和区间的左右端点。

分析:首先预处理前缀和,用pair数组p保存前缀和及其对应的下标。然后对p按前缀和从小到大排序,排序后就可以用尺取法查询。

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;const int inf=0x3f3f3f3f;const int maxn=100005;int a[maxn];pair<int,int> p[maxn];int n,k;void query(int x){    int i=0,j=1,dis=inf;    int ans,ansi,ansj;    while(i<=n&&j<=n)    {        int t=p[j].first-p[i].first;        if(abs(t-x)<=dis)        {            dis=abs(t-x);            ans=t;            ansi=p[i].second;   ansj=p[j].second;            if(ansi>ansj) swap(ansi,ansj);        }        if(t>x) i++;        else if(t<x) j++;        else break;        if(i==j) j++; //注意当i=j时此时sum=0,不存在这样的情况    }    printf("%d %d %d\n",ans,ansi+1,ansj);}int main(){    while(~scanf("%d%d",&n,&k)&&(n||k))    {        int sum=0;        p[0]=make_pair(0,0);        for(int i=1;i<=n;i++)        {            scanf("%d",a+i);            sum+=a[i];            p[i]=make_pair(sum,i);        }        sort(p,p+n+1);        while(k--)        {            int t;            scanf("%d",&t);            query(t);        }    }    return 0;}


0 0