尺取法拓展。
观察奇怪的地方:绝对值大小。
前缀和的原理是 sum[r] - sum[l] + num[l] 代表 l~r 的和
于是我们此题求 那个区间就用此原理。
我们可以知道 |sum[l] - sum[r]| = |sum[r] - sum[l]|
又因为是求绝对值大小,所以说sort 完之后直接 尺取法就可以了!
代码:
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;
struct P{
int sum, p, size;
}num[MAXN];
bool cmp(P a, P b)
{
return a.sum < b. sum;
}
int main()
{
int n, k;
while(cin >> n >> k && n && k)
{
memset(num,0,sizeof(num));
num[0] = (P){0,0,0};
for(int i = 1; i <= n; i ++)
{
scanf("%d",&num[i].size);
num[i].p = i;
num[i].sum = num[i-1].sum + num[i].size;
}
sort(num,num+n+1,cmp);
while(k--)
{
int ansl, ansr, s, sum, ans, maxn = 0x3f3f3f3f, l = 0, r = 1;
scanf("%d",&s);
while(r <= n && maxn)
{
sum = num[r].sum - num[l].sum;
if(abs(sum-s) < maxn)
{
maxn = abs(sum-s);
ans = sum;
ansl = num[l].p;
ansr = num[r].p;
}
if(sum < s)
r ++;
if(sum > s)
l ++;
if(l == r)
r ++;
}
if(ansl > ansr)
swap(ansl,ansr);
printf("%d %d %d\n",ans,ansl+1,ansr);
}
}
return 0;
}
/*
10 1
-9 8 -7 6 -5 4 -3 2 -1 0
11
*/