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