POJ 2018 Best Cow Fences + UVA Live 4726 Average 斜率优化DP

Best Cow Fences
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 11221 Accepted: 3681

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



前一道题目是求一串数中长度大于L的子序列的最大平均值,后一道题在这个基础上,要求输出序列的头和尾的位置。

先看POJ 2018.

先令前缀和为sum[i].若此时序列结尾为点 i , j < k 且在 k 比 j 处决策更优,则容易推得:

sum[i]-sum[k]/i-k > sum[i]-sum[j]/i-j

此时可以用斜率优化,利用单调队列排除点 j .


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn=100005,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
ll sum[maxn],dp[maxn],q[maxn],pos[maxn]; 

ll returnx(ll j,ll k) {
	return j-k;
}

ll returny(ll j,ll k) {
	return sum[j]-sum[k];
}

int main() {
		int n,i,j,l,h,t;
		ll x;
		scanf("%d%d",&n,&l);
		getchar();
		sum[0]=dp[0]=0;pos[0]=-1;
		for (i=1;i<=n;i++) {
			scanf("%lld",&x);
			sum[i]=sum[i-1]+x;
		}
		h=1;t=0;q[0]=0;
		mem0(q);
		ll ans=0;
		for (i=l;i<=n;i++) {
			while (t+1<h&&(sum[i]-sum[q[t+1]])*(i-q[t])>=(sum[i]-sum[q[t]])*(i-q[t+1]))
			    t++;
			dp[i]=sum[i]-sum[q[t]];
			pos[i]=q[t];
			if (dp[i]*(ans-pos[ans])>dp[ans]*(i-pos[i])) ans=i;
			while (t+1<h&&(returny(q[h-1],q[h-2])*returnx(i-l+1,q[h-1])>=returny(i-l+1,q[h-1])*returnx(q[h-1],q[h-2]))) 
				h--;
			q[h]=i-l+1;
			h++;
		}
		printf("%lld\n",1000*dp[ans]/(ans-pos[ans]));
	return 0;
}


https://icpcarchive.ecs.baylor.edu/external/47/4726.pdf


4726 Average


A DNA sequence consists of four letters, A, C, G, and T. The GC-ratio of a DNA sequence is the
number of Cs and Gs of the sequence divided by the length of the sequence. GC-ratio is important
in gene fnding because DNA sequences with relatively high GC-ratios might be good candidates for
the starting parts of genes. Given a very long DNA sequence, researchers are usually interested in
locating a subsequence whose GC-ratio is maximum over all subsequences of the sequence. Since short
subsequences with high GC-ratios are sometimes meaningless in gene fnding, a length lower bound is
given to ensure that a long subsequence with high GC-ratio could be found. If, in a DNA sequence,
a 0 is assigned to every A and T and a 1 to every C and G, the DNA sequence is transformed into a
binary sequence of the same length. GC-ratios in the DNA sequence are now equivalent to averages in
the binary sequence.


Position
Index
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1 2 3 4 5 6 7 8 9
Sequence 0 0 1 0 1 0 1 1 0 1 1 0 1 1 0 1 0

For the binary sequence above, if the length lower bound is 7, the maximum average is 6/8 which
happens in the subsequence [7,14]. Its length is 8, which is greater than the length lower bound 7. If
the length lower bound is 5, then the subsequence [7,11] gives the maximum average 4/5. The length
is 5 which is equal to the length lower bound. For the subsequence [7,11], 7 is its starting index and 11
is its ending index.


Given a binary sequence and a length lower bound
L, write a program to fnd a subsequence of the
binary sequence whose length is at least
L and whose average is maximum over all subsequences of the
binary sequence. If two or more subsequences have the maximum average, then fnd the shortest one;
and if two or more shortest subsequences with the maximum average exist, then fnd the one with the
smallest starting index.



Input


Your program is to read from standard input. The input consists ofT test cases. The number of test
cases
T is given in the frst line of the input. Each test case starts with a line containing two integers
n (1 n 100;000)and L (1L 1;000)which are the length of a binary sequence and a length
lower bound, respectively. In the next line, a string, binary sequence, of length
n is given.


Output


Your program is to write to standard output. Print the starting and ending index of the subsequence.


而求位置则更简单,直接输出pos即可。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn=100005,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
ll sum[maxn],dp[maxn],q[maxn],pos[maxn]; 

ll returnx(ll j,ll k) {
	return j-k;
}

ll returny(ll j,ll k) {
	return sum[j]-sum[k];
}

int main() {
	int cas;
	scanf("%d",&cas);
	while (cas--) {
		int n,i,j,l,h,t;
		char c;
		scanf("%d%d",&n,&l);
		getchar();
		sum[0]=dp[0]=0;
		for (i=1;i<=n;i++) {
			scanf("%c",&c);
			sum[i]=sum[i-1]+c-'0';
		}
		h=1;t=0;q[0]=0;
		mem0(q);
		for (i=l;i<=n;i++) {
			while (t+1<h&&(sum[i]-sum[q[t+1]])*(i-q[t])>=(sum[i]-sum[q[t]])*(i-q[t+1]))
			    t++;
			dp[i]=sum[i]-sum[q[t]];
			pos[i]=q[t];
			while (t+1<h&&(returny(q[h-1],q[h-2])*returnx(i-l+1,q[h-1])>=returny(i-l+1,q[h-1])*returnx(q[h-1],q[h-2]))) 
				h--;
			q[h]=i-l+1;
			h++;
		}
		ll ans=l;
		for (i=l+1;i<=n;i++) {
			if (dp[i]*(ans-pos[ans])>dp[ans]*(i-pos[i])||
			(dp[i]*(ans-pos[ans])==dp[ans]*(i-pos[i])&&i-pos[i]<ans-pos[ans]))
			ans=i;
		}
		printf("%lld %lld\n",pos[ans]+1,ans);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值