POJ 2566 Bound Found 思维+取尺法

题意:给你一个大小为N 的数组,和一个 K (k次询问),每次询问输入一个t,在数组中寻找一个连续区间使得区间和的绝对值与t的差值尽量小,输出差值大小和区间的左右端点。

当时认为自己了解一点点尺取法,结果发现自己根本不怎么会

推荐博客:https://blog.csdn.net/consciousman/article/details/52348439

思路:这道题用到了尺取法单调性的性质,如果直接对数组进行尺取的话,不满足约束条件(头尾枚举的序列满足某种单调的性质,这样才能进行尺取的操作,如果当前的尾状态不满足约定条件的话,如果保证头不变,之后的尾状态也肯定不满足题意。)

我们可以求一个前缀和(然后排序),用前缀和进行尺取,我们顺便记录下标,则我们取得则是区间 [i+1,j] 的和,然后在判断条件来约束i,j。

完整代码:

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=exp(1.0);
const int mod=1e9+7;
const int INF=0x3f3f3f3f;


struct node
{
    int pre;
    int sign;
}know[100005];

bool cmp(node a,node b)
{
    return a.pre<b.pre;
}

int main()
{
    int x,y,n,t,s;
    while(scanf("%d %d",&n,&t)!=EOF,n+t)
    {
        know[0]= {0,0};
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&x);
            know[i]=node{know[i-1].pre+x,i};    ///记录前缀和
        }
        sort(know,know+1+n,cmp);
        while(t--)
        {
            scanf("%d",&s);
            int i=0,j=0,ans=1000000007,maxn=1000000007;
            while(i<=n&&j<=n&&maxn)///如果差值0结束。
            {
                if(i==j)
                    j++;        ///如果i,j相等则表示区间为空
                else
                {
                    int sum=know[j].pre-know[i].pre;    ///表示区间[i+1,j]的和。
                    if(maxn>abs(sum-s))
                    {
                        ans=sum;
                        maxn=abs(sum-s);
                        x=min(know[i].sign,know[j].sign)+1;
                        y=max(know[i].sign,know[j].sign);
                    }
                    if(sum>s)
                        i++;
                    if(sum<s)
                        j++;
                }
            }
            printf("%d %d %d\n",ans,x,y);
        }
    }
    return 0;

}

猜你喜欢

转载自blog.csdn.net/qq_42211531/article/details/85101278