日常训练 平均数
2017-01-10 18:39
316 查看
题意简述:长度为n的序列,列出所有子串,求第k小的平均值。n≤100000
首先二分答案ave,将每个数都减去ave,平均数小于ave的区间在新的数列里平均数小于0,也就是区间和小于0。将区间做一遍前缀和,每有一对逆序对(包括0号位),就有一个小于0的区间,求逆序对归并树状数组都可。
首先二分答案ave,将每个数都减去ave,平均数小于ave的区间在新的数列里平均数小于0,也就是区间和小于0。将区间做一遍前缀和,每有一对逆序对(包括0号位),就有一个小于0的区间,求逆序对归并树状数组都可。
#include<bits/stdc++.h> #define ll long long #define MAXN 100050 using namespace std; struct rec{ double s; int num; }; rec c[MAXN]; int tr[MAXN],a[MAXN],n,k; bool cmp(rec a,rec b){ return a.s > b.s; } int query(int x){ if (x == 0) return 0; return tr[x] + query(x - (x & -x)); } void modify(int x){ if (x > n + 1) return; tr[x]++; modify(x + (x & -x)); } ll check(double ave){ c[0].s=0; for (int i = 1;i <= n;i++) c[i].s = c[i - 1].s + a[i] - ave; for (int i = 0;i <= n;i++) c[i].num = i; sort(c,c + n + 1,cmp); memset(tr,0,sizeof(tr)); ll cnt=0; for (int i = 0;i <= n;i++){ cnt += query(c[i].num + 1); modify(c[i].num + 1); } return cnt; } int main(){ freopen("ave.in","r",stdin); freopen("ave.out","w",stdout); scanf("%d%d",&n,&k); for (int i=1;i <= n;i++) scanf("%d",&a[i]); double l,r,mid; l=0;r=1e9; while (l+1e-5<r){ mid=(l+r)/2; if (check(mid)>=k) r=mid; else l=mid; } printf("%.4lf\n",l); }
相关文章推荐
- 日常训练 20170531 探险
- 日常训练 20170606 魔法手镯
- 日常训练 20161102 隔离区
- 日常训练 20170708 贝加尔湖畔baikal
- [日常训练] 单词
- [日常训练] 独立集
- 日常训练 巨神兵 obelisk
- 日常训练—cf 2017 USP Try-out
- 日常训练 20170606 极地旅行社
- [日常训练] 我们爱序列
- HEU日常训练10.02
- [日常训练] 联络网
- [日常训练] 秀姿势
- [日常训练] CZA的蛋糕
- QUST日常训练(1)北极熊和大象
- 日常训练20161012 方块游戏
- 日常训练20161014 成绩调研
- [日常训练] Tree
- [日常训练] 坦克
- [日常训练] 最小生成树