【题意】题意就是找一个连续的子区间,使它的和的绝对值最接近X。

【分析】这题的做法是先预处理出前缀和,然后对前缀和进行排序,再用尺取法贪心的去找最合适的区间,要注意的是尺取法时首尾指针一定不能相同,因为这时区间相减结果为0,但实际上区间为空,这是不存在的,可能会产生错误的结果。处理时,把(0,0)这个点也放进数组一起排序,比单独判断起点为1的区间更方便。还有ans初始化的值INF一定要大于t的最大值。最后说说这个题最重要的突破口,对前缀和排序。为什么这么做是对的呢?以为这题是取区间的和的绝对值,所以所以用sum[r]-sum[l] 和 sum[l]-sum[r]是没有区别的。这样排序后,把原来无序的前缀和变成有序的了,就便于枚举的处理,并且不影响最终结果。这题的做法是先预处理出前缀和,然后对前缀和进行排序,再用尺取法贪心的去找最合适的区间,要注意的是尺取法时首尾指针一定不能相同,因为这时区间相减结果为0,但实际上区间为空,这是不存在的,可能会产生错误的结果。处理时,把(0,0)这个点也放进数组一起排序,比单独判断起点为1的区间更方便。还有ans初始化的值INF一定要大于t的最大值。最后说说这个题最重要的突破口,对前缀和排序。为什么这么做是对的呢?以为这题是取区间的和的绝对值,所以所以用sum[r]-sum[l] 和 sum[l]-sum[r]是没有区别的。这样排序后,把原来无序的前缀和变成有序的了,就便于枚举的处理,并且不影响最终结果。

【AC代码】

#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100010;
int a[maxn];
int n,k,x;
pair <int,int> P[maxn];
void query_ans(int x){
    int l=0,r=1,minn=inf;
    int ansl,ansr,ans;
    while(l<=n && r<=n){
        int temp = P[r].first-P[l].first;
        if(abs(temp-x)<minn){
            minn = abs(temp-x);
            ans = temp;
            ansl = P[l].second;
            ansr = P[r].second;
        }
        if(temp>x) l++;
        else if(temp<x) r++;
        else break;
        if(l==r) r++;
    }
    if(ansl>ansr) swap(ansl,ansr);
    printf("%d %d %d\n",ans,ansl+1,ansr);
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        if(n==0&&k==0) break;
        P[0] = {0,0};
        int sum=0;
        for(int i=1; i<=n; i++){
            scanf("%d",&a[i]);
            sum+=a[i];
            P[i] = {sum,i};
        }
        sort(P,P+n+1);
        while(k--){
            scanf("%d",&x);
            query_ans(x);
        }
    }
    return 0;
}