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; }