题意 : 给你n个数字,这些数字可正可负,再给你个数字t,
求在这个数列中一个连续的子序列,和的绝对值 与t相差最小;
数据范围较大, 考虑数字没有负数的情况,
能够想到用尺取法解决, (关于尺取法, 自己感受一下这东西的奇妙, 不好说, 理解了之后也没什么好说, 实现主要是首尾指针的移动), 那么增加了负数之后, 发现题目中要的是序列的绝对值, 发现直接排序前缀和即使用后面的前缀和减去前面的前缀和, 也没有关系;
但主要需要注意的是本题细节比较烦, 在POJ上WA了3,4次, 这里提示一下
注意如果给出的值为0时的处理, 还有就是自己多想几组小数据来调试, 调的很恶心, 但也很享受, 适合做尺取的好题
/*
*题意:给你n个数字,这些数字可正可负,再给你个数字t,
*求在这个数列中一个连续的子序列,和的绝对值 与t相差最小
* ————Galaxy TODO
*/
#include <cstdio>
#include <algorithm>
typedef long long LL;
const int N = 1e5 + 10;
#define C c = getchar()
#define rep(i, s, t) for(int i = s; i <= t; ++i)
LL abs(LL x) {return x>0?x:-x;}
int read(int x=0, int t=1) {char C;
while(c<'0' || c>'9') {if(c=='-') t=-1; C;}
while(c>='0' && c<='9') x = x*10 + c-'0', C;
return x*t;
}
struct Sum_tot{
LL sum; int rk;
//Sum_tot(int _sum, int _rk) {sum = _sum; rk = _rk;}
bool operator < (const Sum_tot& rhs) const{
return sum < rhs.sum;
}
}P[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("res.out", "w", stdout);
#endif
int n, T; LL S;
while(scanf("%d%d", &n, &T) == 2 && n+T) {
P[0].sum = 0, P[0].rk = 0;
rep(i, 1, n) P[i] = ((Sum_tot) {P[i-1].sum+read(), i});
std :: sort(P, P+n+1);
// rep(i, 0, n) printf("%lld%c", P[i].sum, i^n?' ':'
');
while(T--) {
scanf("%lld", &S);
int ansl=n, ansr=n;
int l = n-1, r = n;
LL res = 1LL << 62;
while(r > l) {
// printf("%d %d__debug1
", l, r);
while(P[r].sum - P[l].sum <= S && l >= 0) {
if(abs(P[r].sum-P[l].sum-S) < abs(S-res)) {
res = P[r].sum - P[l].sum;
ansl = P[l].rk, ansr = P[r].rk;
}
--l;
}
if(l < 0) break;
// printf("%d %d__debug2
", l, r);
while(P[r].sum - P[l].sum >= S && r > l) {
if(P[r].sum-P[l].sum-S < abs(res-S)) {
res = P[r].sum - P[l].sum;
ansl = P[l].rk, ansr = P[r].rk;
}
--r;
}
if(r < 0) break;
if(l == r) --l;
if(l < 0) break;
// printf("%d %d__debug3
", l, r);
if(res == S) break;
}
if(ansl+1 > ansr) std::swap(ansl, ansr);
printf("%lld %d %d
", res, ansl+1, ansr);
}
}
return 0;
}
//XXX