poj 2566 Bound Found ( 尺取法 )
题意:
给出n个数,求n个数的一个非空区间,使得区间内各个数和的绝对值 与 给定的非负整数t 最接近。
分析:
首先求前缀和。由于是绝对值与t比较,所以左右断点交换没有影响,故可以将求好的前缀和排序。
然后用尺取法。如果当前区间各个数和的绝对值小于ans则更新。
比较 当前区间各个数的和 与t的大小 改变区间的左右端点。
比t大,则左端点++ ; 否则,右端点++。
涉及long long 的绝对值还是手写函数比较好= =!
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 //#include<cstdlib> 6 //#include<cmath> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<set> 11 12 using namespace std; 13 14 typedef long long ll; 15 16 ll a[100010]; 17 pair<ll,int> p[100010]; 18 int n,k; 19 20 ll Abs(ll x) 21 { 22 return x>=0?x:(-x); 23 } 24 void solve(ll x) 25 { 26 int i=0,j=1,le,ri; 27 ll ans = (1<<30),v; 28 while(j<=n && ans) 29 { 30 ll tmp = Abs(p[j].first-p[i].first); 31 if(Abs(tmp-x)<ans) 32 { 33 le = p[i].second; 34 ri = p[j].second; 35 ans = Abs(tmp-x); 36 v = tmp; 37 } 38 if(tmp<x) j++; 39 if(tmp>x) i++; 40 if(i==j) j++; 41 } 42 if(le>ri) 43 { 44 int t = ri; 45 ri = le; 46 le = t; 47 } 48 printf("%lld %d %d\n",v,le+1,ri); 49 } 50 51 int main() 52 { 53 ll x; 54 while(~scanf("%d%d",&n,&k)) 55 { 56 if(n==0 && k==0) 57 break; 58 59 ll sum = 0; 60 p[0] = make_pair(0,0); 61 for(int i=1;i<=n;i++) 62 { 63 scanf("%lld",&a[i]); 64 sum += a[i]; 65 p[i] = make_pair(sum,i); 66 } 67 68 sort(p,p+n+1); 69 while(k--) 70 { 71 scanf("%lld",&x); 72 solve(x); 73 } 74 } 75 return 0; 76 }