码迷,mamicode.com
首页 > 其他好文 > 详细

POJ_2566_Bound_Found

时间:2016-04-23 01:33:15      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

描述


http://poj.org/problem?id=2566

分析


尺取法.

一眼看过去就是用尺取法找和t绝对值相差最小的区间和,但是这道题里的序列并不是非负的,这意味着固定左端点,移动右端点时,区间和不是单调递增的.尺取法的模板题中区间和是单调的,所以找到大于某一值的区间右端点就可以固定.而这道题中因为存在负值,所以区间的变化不是单调的,不能按照普通的方法解决.我们考虑一段区间和,不仅可以认为是a[l]+a[l+1]+...+a[r],还可以看作是sum[r]-sum[l-1],而这道题中要求的区间和的绝对值,就可以看作是max(sum[r],sum[l-1])-min(sum[r],sum[l-1]).这样求一个前缀和,进行排序,双指针确定区间左右端点,这样sum[r]-sum[l](排序后的编号)就代表一个区间和的绝对值,这样的区间就是单调的.如此一来,确定左端点,移动右端点,sum[r]-sum[l]就是单增的,找到sum[r]-sum[l]>t的位置即可停止,然后l++,sum[r-1]-sum[l]比之前的sum[r-1]-sum[l]更小(减数增大),本来就比t小,现在小得更多了,对于任意r‘<=r-1都是如此,就不必考虑,从sum[r]-sum[l]开始继续即可.

 

注意:

1.sum[r]-sum[l-1],因为1<=l<=r,所以l-1>=0,注意sum[0].s=0,sum[0].num=0,要参与排序,并且每一次都要重现赋值,因为上一组数据排序后sum[0].s不一定是0,这将影响到语句"sum[i]=point(sum[i-1].s,i)" .

2.对于区间右端点表示的状态,最好是用来表示当前右端点的位置,然后每一次更新状态时都要判断,与ans比较,看是否更新最优解.

3.由于r>=l所以r>l-1,也就是说两个区间端点不能使同一个点,当l追上r时,r++.

4.其实尺取法的写法可以优化,现在的写法是两层循环,l改变后进行一次操作,然后对于同一个l改变r,每次进行一次操作,这样在一个外层循环内部要写两遍操作.其实对于l和r的改变是一样,都是区间状态的改变,所以只要一层循环即可.

eg:  while (l<=n&&r<=n&&ans!=0) 

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 using std :: sort;
 5 using std :: min;
 6 using std :: max;
 7 
 8 const int maxn=100005,INF=0x7fffffff;
 9 
10 int a[maxn],s[maxn];
11 int n,q,t;
12 
13 struct point
14 {
15     int s,num;
16     point() {}
17     point(int a,int b) : s(a) , num(b) {}
18 }sum[maxn];
19 
20 bool comp(point x,point y) { return x.s<y.s; }
21 
22 int value(int l,int r) { return abs(sum[r].s-sum[l].s); }
23 
24 int L(int l,int r) { return min(sum[l].num,sum[r].num)+1; }
25 
26 int R(int l,int r) { return max(sum[l].num,sum[r].num); }
27 
28 
29 void solve(int t)
30 {
31     int ans=INF,res,idxl,idxr;
32     int r=1;
33     for(int l=0;l<=n;l++)
34     {    
35         if(l==r) r++;
36         if(r>n) break;
37         int now=value(l,r);
38         int d=abs(now-t);
39         if(d<=ans)
40         {
41             ans=d;
42             res=now;
43             idxl=L(l,r);
44             idxr=R(l,r);
45         }
46         while(r<n&&now<t)
47         {
48             r++;
49             now=value(l,r);
50             int d=abs(now-t);
51             if(d<=ans)
52             {
53                 ans=d;
54                 res=now;
55                 idxl=L(l,r);
56                 idxr=R(l,r);
57             }
58         }
59         if(now<t) break;        
60         if(now==t)
61         {
62             break;
63         }
64     }
65     printf("%d %d %d\n",res,idxl,idxr);
66 }
67 
68 void init()
69 {
70     while(scanf("%d%d",&n,&q)&&(n!=0||q!=0))
71     {
72         sum[0].s=0;
73         sum[0].num=0;
74         for(int i=1;i<=n;i++)
75         {
76             scanf("%d",&a[i]);
77             sum[i]=point(sum[i-1].s+a[i],i);
78         }
79         sort(sum,sum+n+1,comp);
80         for(int i=1;i<=q;i++)
81         {
82             scanf("%d",&t);
83             solve(t);
84         }
85     }
86 }
87 
88 int main()
89 {
90     freopen("bound.in","r",stdin);
91     freopen("bound.out","w",stdout);
92     init();
93     fclose(stdin);
94     fclose(stdout);
95     return 0;
96 }
View Code

 

POJ_2566_Bound_Found

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5423228.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!