您的位置:首页 > 其它

ACM: uva 1451 - Average

2016-05-19 23:28 232 查看
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
finding 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 finding, 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.
 

Position11111111
Index12345678901234567
Sequence00101011011011010
 
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 find 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 find the shortest one; and if two or
more shortest subsequences with the maximum average exist, then
find the one with the smallest starting index.
Input 
Your program
is to read from standard input. The input consists
of T test cases. The number of test
cases T is given in the first 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
length n is given.
Output 
Your program
is to write to standard output. Print the s
4000
tarting and ending index
of the subsequence.
The following
shows sample input and output for two test cases.
Sample Input 

17

00101011011011010 
20

11100111100111110000
Sample Output 
7
11 
6
9
 
题意: 给出一个长度为n的01序列,
要你求出一段至少长度为L的连续子序列, 该子序列的数字的平均值
   
  最大,
多解尽量保证长度小, 在保证起点编号尽量小, 求出起点和终点编号.
 
解题思路:
     
1. 这题是一道数形结合的问题, 我从《浅谈数形结合思想在信息学竞赛中的应用》学习而得算法.
   
  设Sum[i] = a1+a2+...+ai,
那么平均值ave(i,j) =
(sum[j]-sum[i-1])/(j-(i-1));
   
  容易发现问题可以转换为:
求函数function(i,
Sum[i])的任意两点的最大斜率.
具体可以从学习
   
  上面提到的《浅谈数形结合思想在信息学竞赛中的应用》讲解, 我只提出一点就是:
维护下凸曲线
     
 例如: 

明显斜率K(j,i)>K(k,j),
K(i,k)
     
 无法确定更大的斜率K,j点可以说是多余的,
因此要维护下凸曲线(斜率逐渐变大的曲线).
     
 2. 题目到这里其实可以做了,
用单调队列就可以了.
 
代码:
 

#include <cstdio>

#include <iostream>

#include <cstring>

using namespace std;

#define MAX 100010

int n, L;

char str[MAX];

int sum[MAX], qu[MAX];

double ans;

inline double getK(int i, int j)

{

 return (sum[j]-sum[i])*1.0/(j-i);

}

int main()

{

// freopen("input.txt", "r", stdin);

 int caseNum, i;

 scanf("%d", &caseNum);

 while(caseNum--)

 {

  scanf("%d %d",
&n, &L);

  scanf("%s", str+1);

  memset(sum, 0,
sizeof(int)*(n+5));

  memset(qu, 0,
sizeof(int)*(n+5));

  for(i = 1; i <=
n; ++i)

   sum[i] =
sum[i-1]+str[i]-'0';

  int len = L;

  ans = getK(0, L);

  int start = 0, end = L;

  int front = 0, rear = -1;

  for(i = L; i <=
n; ++i)

  {

   int temp =
i-L;

   //维护下凸曲线

   while(front
< rear &&
getK(qu[rear], temp) <= getK(qu[rear-1],
qu[rear]))

    rear--;

   qu[++rear] =
temp;

   //将不又是当前最优的点,
从队列里面删除

   while(front
< rear &&
getK(qu[front], i) <= getK(qu[front+1], i))

    front++;

   double t =
getK(qu[front], i);

   if(t == ans
&& len >
i-qu[front])

   {

    len
= i-qu[front];

    start
= qu[front];

    end
= i;

   }

   else if(t
> ans)

   {

    ans
= t;

    len
= i-qu[front];

    start
= qu[front];

    end
= i;

   }

  }

  printf("%d %d\n", start+1,
end);

 }

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: