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 }

 

posted @ 2015-03-25 14:48  fukan  阅读(308)  评论(0编辑  收藏  举报