【题意】题意就是找一个连续的子区间,使它的和的绝对值最接近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;
}