Bound Found
题意:
给出一个序列,要求找到一个子区间,使得所有数之和的绝对值与t相差最小,如果有多种情况,输出任意一种。
分析:
既然要找到一个和与t最接近的子区间,那我们就不断找和比当前区间大的区间,当和大于等于t时,就不需要寻找了。然后左端点右移,根据尺取法,不断寻找最优子区间。看的大佬的题解……
参考资料:大佬博客
代码:
#include <map> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e6+100; const int inf=0x7FFFFFFF; int a[maxn]; struct Interval { int l,r,sum; bool operator < (const Interval& rhs) const { return sum<rhs.sum; } }; Interval interval[maxn]; int cal(int a,int b) { return abs(abs(a)-b); } void solve(int t,int n) { int s=0,e=1,l,r; int minsub=inf,sum,ans; while(e<=n) { sum=interval[e].sum-interval[s].sum; if(minsub>cal(sum,t)){ ans=abs(sum); l=interval[s].r; r=interval[e].r; minsub=cal(sum,t); } if(sum<t) e++; else if(sum>t) s++; else break; if(s==e) e++; } printf("%d %d %d ",ans,min(l,r)+1,max(l,r)); } int main() { // freopen("in.txt","r",stdin); int n,k,t; while(scanf("%d%d",&n,&k)!=EOF&&n&&k) { interval[0].l=interval[0].r=interval[0].sum=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); interval[i].l=1;interval[i].r=i; if(i==1) interval[i].sum=a[i]; else interval[i].sum=interval[i-1].sum+a[i]; } sort(interval,interval+n+1); for(int i=1;i<=k;i++){ scanf("%d",&t); solve(t,n); } } return 0; }