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.
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.
* 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 }