POJ2018 Best Cow Fences —— 斜率优化DP

题目链接:https://vjudge.net/problem/POJ-2018

 

Best Cow Fences
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 11394   Accepted: 3736

Description

Farmer John's farm consists of a long row of N (1 <= N <= 100,000)fields. Each field contains a certain number of cows, 1 <= ncows <= 2000. 

FJ wants to build a fence around a contiguous group of these fields in order to maximize the average number of cows per field within that block. The block must contain at least F (1 <= F <= N) fields, where F given as input. 

Calculate the fence placement that maximizes the average, given the constraint. 

Input

* Line 1: Two space-separated integers, N and F. 

* Lines 2..N+1: Each line contains a single integer, the number of cows in a field. Line 2 gives the number of cows in field 1,line 3 gives the number in field 2, and so on. 

Output

* Line 1: A single integer that is 1000 times the maximal average.Do not perform rounding, just print the integer that is 1000*ncows/nfields. 

Sample Input

10 6
6 
4
2
10
3
8
5
9
4
1

Sample Output

6500

Source

 

 

题意:

给出一个序列,求一段个数大于等于F的子序列,使得它的(和/个数)最大。

 

题解:

1.最暴力的做法是:先求出前缀和,再枚举序列的起点终点。时间复杂度为O(n^2),因此不能通过。

2.我们可以把前缀和sum[i]看作是坐标轴的y坐标,个数i看作是坐标轴的x坐标。这样就转化为求:(sum[i]-sum[j])/(i-j)最大,显然这是一个斜率的表达式,因而要求的是最大斜率。

3.根据第2点,我们可以用斜率进行优化:由于求的是最大斜率,因而备选点要维持下凸性。

4.关于每组的个数最少为F的处理,详情在:HDU3045 Picnic Cows 

 

 

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int mod = 1e9+7;
17 const int MAXM = 1e5+10;
18 const int MAXN = 1e5+10;
19 
20 double sum[MAXN], dp[MAXN];
21 int head, tail, q[MAXN];
22 
23 double slope(int i, int j)  //斜率
24 {
25     return (sum[j]-sum[i])/(j-i);
26 }
27 
28 int main()
29 {
30     int n, F;
31     while(scanf("%d%d",&n,&F)!=EOF)
32     {
33         sum[0] = 0;
34         for(int i = 1; i<=n; i++)
35         {
36             int val;
37             scanf("%d", &val);
38             sum[i] = sum[i-1] + val;
39         }
40 
41         double ans = 0;
42         head = tail = 0;
43         q[tail++] = 0;
44         for(int i = F; i<=n; i++)
45         {
46             while(head+1<tail && slope(q[head],i)<slope(q[head+1], i))  head++;
47             ans = max(ans, slope(q[head],i));
48 
49             int j = i-F+1;  //不能直接放i,因为要求了每一组至少为F,故i不能为i+1转移。
50             while(head+1<tail && slope(q[tail-1], j)<slope(q[tail-2],q[tail-1])) tail--;
51             q[tail++] = j;
52         }
53 
54         printf("%d\n", (int)(ans*1000));
55     }
56 }
View Code

 

posted on 2018-01-06 00:49  h_z_cong  阅读(380)  评论(0编辑  收藏  举报

导航