題意
給一串數列,再給一個目標值(非負),求這個數列中最接近目標值的區間和的絕對值
分析
原數列中的數有正有負,用Two Pointers不能保證向左向右移動一定會使區間和變大或變小,而排序又會打亂數列的順序。同樣,如果先算出前綴和,在前綴和上移動同樣不能保證向着期望的方向變化。但是,對前綴和排序不影響結果,只要記錄某個前綴和對應的原下標,排序後再用Two Pointers,就可以解決這個問題
AC代碼
//POJ 2566 Bound Found
//AC 2016-8-1 14:48:13
//Two Pointers
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;
#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define bug cout<<"here"<<endl;
//#define debug
struct psum
{
int v;
int pos;
bool operator< (const psum &rhs) const
{
if(v==rhs.v)
return pos<rhs.pos;
return v<rhs.v;
}
}prefix[100010];
int n,k;
int main()
{
#ifdef debug
freopen("E:\\Documents\\code\\input.txt","r",stdin);
freopen("E:\\Documents\\code\\output.txt","w",stdout);
#endif
while(scanf("%d %d",&n,&k)!=EOF&&n+k)
{
int sum=0,t;
for(int i=1;i<=n;++i)
{
scanf("%d",&t);
sum+=t;
prefix[i].pos=i;
prefix[i].v=sum;
}
prefix[0].v=prefix[0].pos=0;
sort(prefix,prefix+n+1);
while(k--)
{
scanf("%d",&t);
int p=1,q=0;
int res=-INF,fp,fq,cur;
while(p<=n&&q<=n)
{
cur=prefix[p].v-prefix[q].v;
if(abs(cur-t)<abs(res-t))
{
res=cur;
fp=p;
fq=q;
}
if(cur<t) ++p;
else if(cur>t) ++q;
else break;
if(p==q) ++p;
}
p=max(prefix[fp].pos,prefix[fq].pos);
q=min(prefix[fp].pos,prefix[fq].pos)+1;
printf("%d %d %d\n",res,q,p);
}
}
return 0;
}