T1: 平均数
分析:这个题昨天考试的时候一看就想到了之前做过两次的一个题型,但是似乎没有办法用两个指针一起扫的方法解决, 感觉平均数这个东西怪怪的没有单调性, 于是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 }