一开始没有用前缀和处理,发现如果数据里带负数的话,快慢指针的移动判定条件不好写。如果暴力枚举起点的话,那么和暴力的o(n^2)没有任何本质区别。后面发现可以用前缀和进行优化,这样子的话就可以到了一个o(n)的级别(区间i,j和=j前缀和-i前缀和),因此只要判断当前区间和与记录答案进行比较就可以了。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define inf 0x3f3f3f3f
const int maxn = 500010;
using namespace std;
int a[maxn];
struct node{
int presum,id;
}p[maxn];
int n,m;
int sum;
bool cmp(node a,node b)
{
return a.presum < b.presum;
}
void Find(int tar){
int p1 = 0,p2 = 1,ans = inf,left,right,val,tmp;
while(p2 <= n && ans)
{
tmp = p[p2].presum - p[p1].presum;
if(abs(tmp - tar) < ans)
{
ans = abs(tmp - tar);
val = tmp;
left = p[p1].id;
right = p[p2].id;
}
if(tmp < tar)p2++;
if(tmp > tar)p1++;
if(p1 == p2)p2++;
}
if(left > right)
swap(left,right);
cout<<val<<" "<<left+1<<" "<<right<<endl;
}
int main()
{
while(~scanf("%d%d",&n,&m)&&n&&m)
{
sum = 0;
p[0].presum = 0,p[0].id = 0;
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
sum += a[i];
p[i].presum = sum;
p[i].id = i;
}
sort(p,p+n+1,cmp);
while(m--)
{
int tar;
scanf("%d",&tar);
Find(tar);
}
}
return 0;
}