zoukankan      html  css  js  c++  java
  • POJ2566-Bound Found (尺取法)

    POJ2566-Bound Found

        题目大意:给出一段长度为n的数列,数列中的元素有正有负,求一段连续的区间,使得该区间的和的绝对值最接近给定的值

        尺取法一般适用于对一段连续的区间的和进行处理的情况,反复推进区间复杂度一般为O(n)

        当区间的元素都正整数时,区间和是单调递增的,通过不断向前推进区间的开头s和末尾t来满足题目要求的最优解即为尺取法

        另外对于区间的和可以转化为两个前缀和相减的形式:

        设sum[i]=a[1]+a[2]+....+a[i],(一般把数组下标设为从1开始比较方便处理)

            则区间[s,t]的和=sum[t]-sum[s-1];

            而sum[t]-sum[s]为区间[s+1,t]的和,区间的起点下标一定要注意加1;

        此题可以把区间和转化为前缀和相减的形式,由于是求区间和的绝对值,所以可以对区间和从小到的进行排序,

        (s<t时,abs(sum[t]-sum[s])=abs(sum[s]-sum[t]),与顺序无关),只要用一个pair数组标记一下前缀和的下标即可,

        这时由于该区间是单调递增的,就可以采用尺取法处理了,注意每次推进区间前更新一下最优解.

    if(sum<m)         t++;//区间小了
    else if(sum>m)   s++;//区间大了
    else if(sum==m) break;//找到最优解 

        此题有个比较坑的地方时INF必须开的比2000000000大(0x3f3f3f3f肯定小了),等于或者小余都会wa.

        还有一个比较坑的地方时,给定的t可能为0,而区间不能为0,所以推进区间后要进行一下判断

    if(s==t) t++;

        以下是ac代码

    /*
    * Created:     2016年04月03日 22时33分15秒 星期日
    * Author:      Akrusher
    *
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <deque>
    #include <list>
    #include <set>
    #include <map>
    #include <stack>
    #include <queue>
    #include <numeric>
    #include <iomanip>
    #include <bitset>
    #include <sstream>
    #include <fstream>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    #define in(n) scanf("%d",&(n))
    #define in2(x1,x2) scanf("%d%d",&(x1),&(x2))
    #define in3(x1,x2,x3) scanf("%d%d%d",&(x1),&(x2),&(x3))
    #define inll(n) scanf("%I64d",&(n))
    #define inll2(x1,x2) scanf("%I64d%I64d",&(x1),&(x2))
    #define inlld(n) scanf("%lld",&(n))
    #define inlld2(x1,x2) scanf("%lld%lld",&(x1),&(x2))
    #define inf(n) scanf("%f",&(n))
    #define inf2(x1,x2) scanf("%f%f",&(x1),&(x2))
    #define inlf(n) scanf("%lf",&(n))
    #define inlf2(x1,x2) scanf("%lf%lf",&(x1),&(x2))
    #define inc(str) scanf("%c",&(str))
    #define ins(str) scanf("%s",(str))
    #define out(x) printf("%d
    ",(x))
    #define out2(x1,x2) printf("%d %d
    ",(x1),(x2))
    #define outf(x) printf("%f
    ",(x))
    #define outlf(x) printf("%lf
    ",(x))
    #define outlf2(x1,x2) printf("%lf %lf
    ",(x1),(x2));
    #define outll(x) printf("%I64d
    ",(x))
    #define outlld(x) printf("%lld
    ",(x))
    #define outc(str) printf("%c
    ",(str))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    #define mem(X,Y) memset(X,Y,sizeof(X));
    typedef vector<int> vec;
    typedef long long ll;
    typedef pair<int,int> P;
    const int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    const int INF=3000000000;//开小了会wa
    const ll mod=1e9+7;
    ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
    const bool AC=true;
    int n,m,k;
    P p[100005];
    void solve(){
        int s,t,sum,ms,mt,msum,Min; 
        s=0,t=1;    //s和t分别是左右区间端点
        msum=INF;              
        while(s<=n&&t<=n){
            sum=p[t].first-p[s].first;
            if(abs(sum-m)<abs(msum-m)){
                msum=sum;
                ms=p[s].second;
                mt=p[t].second;//ms,mt存放最优值,ms最后要加1
            }
            if(sum<m) t++;
            else if(sum>m) s++;
            else if(sum==m) break;
            if(s==t) t++;
        }
        if(ms>mt) swap(ms,mt);//注意交换顺序
        printf("%d %d %d
    ",msum,ms+1,mt);
    }
    int main()
    {
        int sum,temp;
        while(in2(n,k)==2){
            if(n==0&&k==0) break;
            p[0]=P(0,0); //这样对pair赋值比较简单
            sum=0;
            rep(i,1,n+1){
                in(temp);
                sum+=temp;
                p[i]=P(sum,i);
            }
            sort(p,p+n+1);//有序数组才能尺取法
            while(k--){
            in(m);
            solve();
            }
        }
        return 0;
    }

        

  • 相关阅读:
    Chrome开发者工具中Elements(元素)断点的用途
    最简单的SAP云平台开发教程
    Java实现 LeetCode 495 提莫攻击
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 492 构造矩形
  • 原文地址:https://www.cnblogs.com/akrusher/p/5351380.html
Copyright © 2011-2022 走看看