POJ - 2566 Bound Found

题目大意:

一个长度为n的序列,你需要要从中找到一个上界r和下界l让[l,r]之间的和的绝对值与t最相近

分析:

尺取法。其实第一感觉就是尺取法,但是如果直接用原序列,原序列不具有单调性,没办法使用尺取法,而这题巧
妙的地方就在于需要用到前缀和。用pair<int,int>sum[]的first存前i个数的和second存i也就是上界
(sum[0]={0,0}),然后将sum排序,再用尺取法就行了,注意[l,r]的区间和,实际上是a[r]-a[l-1],所以
ansl+1.(本题坑点:初始的ans值一定要设的比较大0x3f3f3f3f是不够的)

code:

#define debug
#include<stdio.h>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<functional>
#include<iomanip>
#include<map>
#include<set>
#define pb push_back
#define dbg(x) cout<<#x<<" = "<<(x)<<endl;
#define lson l,m,rt<<1
#define cmm(x) cout<<"("<<(x)<<")";
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int maxn=1e5;
const int INF=0x3f3f3f3f;
const int inf=0x7fffffff;
const int mod=1e9+7;
const int MOD=10007;
//----
//define
PII sum[maxn+10];
int n,k,t;
//solve
void solve() {
	while(cin>>n>>k&&n&&k){
		sum[0]=make_pair(0,0);
		int tot=0;
		for(int i=1;i<=n;i++){
			int tmp;
			cin>>tmp;
			tot+=tmp;
			sum[i]=make_pair(tot,i);
		}
		sort(sum,sum+n+1);
		for(int i=0;i<k;i++){
			cin>>t;
			int l=0,r=1,ans=inf,ansl=0,ansr=0;
			while(r<=n){
				int tmp=sum[r].first-sum[l].first;
				if(abs(tmp-t)<=abs(ans-t)){
					ans=tmp;
					ansl=sum[l].second;
					ansr=sum[r].second;
				}
				if(tmp>t)l++;
				else if(tmp<t)r++;
				else break;
				if(l==r)r++;
			}
			if(ansl>ansr)swap(ansl,ansr);
			cout<<ans<<" "<<ansl+1<<" "<<ansr<<endl;
		}
	}
}

int main() {
	ios_base::sync_with_stdio(0);
#ifdef debug
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	cin.tie(0);
	cout.tie(0);
		solve();
	return 0;
}

 

posted @ 2018-06-12 15:21  visualVK  阅读(150)  评论(0编辑  收藏  举报