您的位置:首页 > Web前端

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

2017-08-22 19:15 597 查看
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

USACO 2003 March Green

前一道题目是求一串数中长度大于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 maxi
4000
mum 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 (1≤
L ≤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 lengthn
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: