T1: 平均数

联赛模拟测试5题解

 

  分析:这个题昨天考试的时候一看就想到了之前做过两次的一个题型,但是似乎没有办法用两个指针一起扫的方法解决, 感觉平均数这个东西怪怪的没有单调性, 于是n^2暴力加信仰剪枝, 40pts get(信仰剪枝怎么没发挥作用!!!)

  这道题还是有区别的,但是和之前学姐讲过的0/1分数规划有很多的相似之处,二分答案是要的,于是我们重点考虑怎么检验,满足条件的区间一定满足(sum[r] - sum[l - 1]) / (r - l + 1) >= x,于是sum[r] - sum[l - 1] >= x * ( r - l + 1); 变形之后有sum[r] - x * r >= sum[r - 1] - x * (l - 1);发现这个似乎是一个逆序对, 于是直接归并排序 / 树状数组就可以了, 但是本题树状数组常数巨大, 于是采用归并的方式进行实现。时间复杂度为O(N(logN) ^ 2), 学长开的3333ms可以稳过。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 const int N = 1e5 + 10;
 5 double a[N], l, r;
 6 typedef long long ll;
 7 ll x[N], sum[N];
 8 ll n, m, res;
 9 double b[N], c[N];
10 void merge_sort(int l, int r) {
11     int mid = (l + r) >> 1;
12     if(l == r) return;
13     merge_sort(l, mid);
14     merge_sort(mid + 1, r);
15     for(int i = l; i <= r; ++i) {
16         if(i <= mid) b[i] = a[i];
17         else c[i] = a[i];
18     }
19     int _l = l, _r = mid + 1, head = l - 1;
20     while(_l <= mid && _r <= r) {
21         if(b[_l] < c[_r]) {
22             a[++head] = b[_l];
23             _l++;
24         }
25         else {
26             a[++head] = c[_r];
27             res += mid - _l + 1;
28             _r++;
29         }
30     }
31     while(_l <= mid) {
32         a[++head] = b[_l++];
33     }
34     while(_r <= r) {
35         a[++head] = c[_r++];
36     }
37 }
38 bool Judge(double pos) {
39     for(int i = 0; i <= n; ++i)
40         a[i] = sum[i] - pos * i;
41     res = 0;
42     merge_sort(0, n);
43     return res >= m;
44 }
45 int main() {
46     freopen("ave.in", "r", stdin);
47     freopen("ave.out", "w", stdout);
48     scanf("%d%d", &n, &m);
49     for(int i = 1; i <= n; ++i)  {
50         scanf("%lld", &x[i]);
51         sum[i] = sum[i - 1] + x[i];
52         if(x[i] > r) r = x[i];
53     }
54     while(r - l > 1e-7) {
55         double mid = (l + r) / 2;
56         if(Judge(mid)) r = mid;
57         else l = mid;
58     }
59     printf("%.4lf\n", l);
60     return 0;
61 }
View Code

相关文章: