[关闭]
@Chilling 2017-08-06T02:12:00.000000Z 字数 3047 阅读 853

HDU-6070: Dirt Ratio (二分 + 线段树)

线段树


Problem Description

In ACM/ICPC contest, the ''Dirt Ratio'' of a team is calculated in the following way. First let's ignore all the problems the team didn't pass, assume the team passed X problems during the contest, and submitted Y times for these problems, then the ''Dirt Ratio'' is measured as XY. If the ''Dirt Ratio'' of a team is too low, the team tends to cause more penalty, which is not a good performance.

此处输入图片的描述
Picture from MyICPC

Little Q is a coach, he is now staring at the submission list of a team. You can assume all the problems occurred in the list was solved by the team during the contest. Little Q calculated the team's low ''Dirt Ratio'', felt very angry. He wants to have a talk with them. To make the problem more serious, he wants to choose a continuous subsequence of the list, and then calculate the ''Dirt Ratio'' just based on that subsequence.

Please write a program to find such subsequence having the lowest ''Dirt Ratio''.

Input

The first line of the input contains an integer , denoting the number of test cases.

In each test case, there is an integer in the first line, denoting the length of the submission list.

In the next line, there are n positive integers , denoting the problem ID of each submission.

Output

For each test case, print a single line containing a floating number, denoting the lowest ''Dirt Ratio''. The answer must be printed with an absolute error not greater than .

Sample Input

1
5
1 2 1 2 3

Sample Output

0.5000000000

Hint

For every problem, you can assume its final submission is accepted.

题意:可以理解为,给出n次提交的题号,每次提交都是AC的,要你选出一段区间,满足这段区间的有效AC率最低,问这个最低有效的AC率是多少。

分析:二分答案mid,通过的题目数量是cnt个,区间长度为r-l+1,那么,移项得到式子。当,二分左区间,否则二分右区间。我们枚举右端点,用线段树维护左边最小值,建树时,初始化为l*mid,对于每个a[i],贡献区间为[pre[a[i]]+1,i],即其上一次出现位置的后一个位置到当前位置,我们把这个区间+1。找到区间最小值,那么就是以当前位置结尾的所有区间中的最小值。


  1. #include <bits/stdc++.h>
  2. #define eps 1e-4
  3. using namespace std;
  4. typedef long long LL;
  5. const int maxn = 6e4 + 10;
  6. int a[maxn], pre[maxn];
  7. int n;
  8. struct node
  9. {
  10. int l, r;
  11. double lazy, minx;
  12. } s[4 * maxn];
  13. void build (int id, int l, int r, double x)
  14. {
  15. s[id].l = l;
  16. s[id].r = r;
  17. s[id].lazy = 0;
  18. if (l == r)
  19. s[id].minx = (double) l * x;
  20. else
  21. {
  22. int mid = (l + r) / 2;
  23. build (id * 2, l, mid, x);
  24. build (id * 2 + 1, mid + 1, r, x);
  25. s[id].minx = min (s[id * 2].minx, s[id * 2 + 1].minx);
  26. }
  27. }
  28. void pushdown (int id)
  29. {
  30. s[id * 2].lazy += s[id].lazy;
  31. s[id * 2 + 1].lazy += s[id].lazy;
  32. s[id * 2].minx += s[id].lazy;
  33. s[id * 2 + 1].minx += s[id].lazy;
  34. s[id].lazy = 0;
  35. }
  36. void update (int id, int l, int r, double val)
  37. {
  38. if (l <= s[id].l && r >= s[id].r)
  39. {
  40. s[id].minx += val;
  41. s[id].lazy += val;
  42. return;
  43. }
  44. pushdown (id);
  45. int mid = (s[id].l + s[id].r) / 2;
  46. if (l <= mid)
  47. update (id * 2, l, r, val);
  48. if (r > mid)
  49. update (id * 2 + 1, l, r, val);
  50. s[id].minx = min (s[id * 2].minx, s[id * 2 + 1].minx);
  51. }
  52. double query (int id, int l, int r)
  53. {
  54. if (l <= s[id].l && s[id].r <= r)
  55. return s[id].minx;
  56. pushdown (id);
  57. int mid = (s[id].l + s[id].r) / 2;
  58. if (r <= mid)
  59. return query (id * 2, l, r);
  60. else if (l > mid)
  61. return query (id * 2 + 1, l, r);
  62. else
  63. return min (query (id * 2, l, r), query (id * 2 + 1, l, r));
  64. }
  65. int check (double mid)
  66. {
  67. memset (pre, 0, sizeof (pre) );
  68. build (1, 1, n, mid);
  69. for (int i = 1; i <= n; i++)
  70. {
  71. int l = pre[a[i]] + 1;
  72. int r = i;
  73. pre[a[i]] = i;
  74. update(1, l, r, 1);
  75. if (query(1, 1, r) <= mid * (r + 1))
  76. return 1;
  77. }
  78. return 0;
  79. }
  80. int main()
  81. {
  82. int t;
  83. scanf ("%d", &t);
  84. while (t--)
  85. {
  86. scanf ("%d", &n);
  87. for (int i = 1; i <= n; i++)
  88. scanf ("%d", &a[i]);
  89. double l = 0, r = 1;
  90. while (r - l > eps)
  91. {
  92. double mid = (l + r) / 2;
  93. if (check (mid) ) r = mid;
  94. else l = mid;
  95. }
  96. printf ("%.10lf\n", l);
  97. }
  98. return 0;
  99. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注