题目大意:就是在给你的数列中取一段,使它和的绝对值最接近于t,并输出他的和的绝对值,区间l和r。
解题思路:一开始说这是一道尺取题,我是不信的,因为没有发现单调性,那我怎么尺取呢,看了别人的题解,才恍然大悟,居然可以对前缀和sum排序,当然下标id是要记住的。然后这时候的sum就有单调性了,我们就可以在sum上进行尺取。l与r,a[r].sum-a[l].sum 就是 a[l].id+1与a[r].id对应的区间的和的绝对值(因为求的是绝对值嘛,那就可以直接大的减小的,和小的减大的取绝对值同效果),如果a[r].sum-a[l].sum>t, l++,反之 r++,并且每次尝试更新。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=1e5+7;
struct node {
int id,sum;
} a[maxn];
int n,k,t;
bool cmp(node x,node y) {
return x.sum<y.sum;
}
void solve() {
int l = 0, r = 1, al, ar, ans, minn = inf;
while (l<=n && r<=n && minn!=0) {
int temp=a[r].sum-a[l].sum;//这里不能用算的时候 l-1 因为这里的l是排序后的数组,已经没有前后逻辑关系
if (abs(temp-t) < minn) {
minn=abs(temp-t);
ar=a[r].id,al=a[l].id;
ans=temp;
}
if (temp > t) l++;
else if (temp < t) r++;
else break;
if (r == l) r++;
}
if(al>ar) swap(al,ar);
cout<<ans<<" "<<al+1<<" "<<ar<<endl; //最后再将al+1
}
int main() {
while(scanf("%d%d",&n,&k)!=EOF) {
if(!n && !k) break;
a[0].sum=0,a[0].id=0; //这里0要加进去,因为算的时候不能l-1了
for(int i=1; i<=n; ++i) {
scanf("%d",&a[i].sum);
a[i].sum+=a[i-1].sum;
a[i].id=i;
}
sort(a,a+1+n,cmp);
while(k--) {
scanf("%d",&t);
solve();
}
}
return 0;
}