POJ 2566 Bound Found 【Two Pointers】
题意
给一串数列,再给一个目标值(非负),求这个数列中最接近目标值的区间和的绝对值
分析
原数列中的数有正有负,用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;
}