poj2566(尺取法)

Bound Found

题意:

  给出一个序列,要求找到一个子区间,使得所有数之和的绝对值与t相差最小,如果有多种情况,输出任意一种。

分析:

  既然要找到一个和与t最接近的子区间,那我们就不断找和比当前区间大的区间,当和大于等于t时,就不需要寻找了。然后左端点右移,根据尺取法,不断寻找最优子区间。看的大佬的题解……

  参考资料:大佬博客

代码:

#include <map>
#include <math.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;
#define ll long long
#define ull unsigned long long
#define cls(x) memset(x,0,sizeof(x))
#define clslow(x) memset(x,-1,sizeof(x))

const int maxn=1e6+100;
const int inf=0x7FFFFFFF;

int a[maxn];

struct Interval {
    int l,r,sum;
    bool operator < (const Interval& rhs) const {
        return sum<rhs.sum;
    }
};
Interval interval[maxn];

int cal(int a,int b)
{
    return abs(abs(a)-b);
}

void solve(int t,int n)
{
    int s=0,e=1,l,r;
    int minsub=inf,sum,ans;
    while(e<=n)
    {
        sum=interval[e].sum-interval[s].sum;
        if(minsub>cal(sum,t)){
            ans=abs(sum);
            l=interval[s].r;
            r=interval[e].r;
            minsub=cal(sum,t);
        }
        if(sum<t)   e++;
        else if(sum>t)  s++;
        else    break;
        if(s==e)    e++;
    }
    printf("%d %d %d\n",ans,min(l,r)+1,max(l,r));
}

int main()
{
//    freopen("in.txt","r",stdin);
    int n,k,t;
    while(scanf("%d%d",&n,&k)!=EOF&&n&&k)
    {
        interval[0].l=interval[0].r=interval[0].sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            interval[i].l=1;interval[i].r=i;
            if(i==1)    interval[i].sum=a[i];
            else        interval[i].sum=interval[i-1].sum+a[i];
        }
        sort(interval,interval+n+1);
        for(int i=1;i<=k;i++){
            scanf("%d",&t);
            solve(t,n);
        }
    }
    return 0;
}
View Code

 

posted on 2018-07-30 10:07  我过了样例耶  阅读(491)  评论(0编辑  收藏  举报

导航