noip模拟 平均数【二分+归并排序】
2018-01-17 16:38
323 查看
Description
有一天,小A得到了一个长度为n的序列。他把这个序列的所有连续子序列都列了出来, 并对每一个子序列
都求了其平均值, 然后他把这些平均值写在纸上, 并对它们进行排序,
最后他报出了第k小的平均值。
你要做的就是模仿他的过程
思路
题解一:实数二分+树状数组+排序。
先分析一下题目,如果是暴利枚举的话肯定会TLE。所以我们只能考虑二分答案,我们二分到一个平均数,如何判断他是否可行呢?加上当前的平均数为x,那么我们对于每一个数都减去x,对于每一个位置求前缀和,然后将得到的前缀和排序。通过前缀和作差我们是可以得到一段区间的总和的,我们要求平均数<=x的子序列个数,那么在所有数减去x的情况下就是求有多少区间的和是<=esp(精度误差),那么我们将前缀和按照从大到小排序,当前位置之前有多少在数列中位置小于当前位置的数就是对答案的贡献,可以用树状数组来统计答案。时间复杂度Θ(k∗n∗(log2n)2)所以这样做在不开O2的情况下会TLE。
代码1
#include <bits/stdc++.h> #define N 100005 #define ll long long #define eps 1e-5 #define min(x,y) (x<y?x:y) #define max(x,y) (x>y?x:y) using namespace std; inline int read(){ int ret=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())ret=(ret<<3)+(ret<<1)+c-'0'; return ret*f; } int n; ll k,a ,tr ; struct pppp{ double x;int pos; }p ; bool cmp(pppp a,pppp b){ return a.x-b.x>eps||a.x-b.x<=eps&&a.x-b.x>=-eps&&a.pos<b.pos; } inline void add(int x){ for(int i=x;i<=n;i+=i&-i)++tr[i]; } inline int qh(int x){ ll an=0; for(int i=x;i;i-=i&-i)an+=tr[i]; return an; } bool check(double x){ p[0].x=0;p[0].pos=0; for(int i=1;i<=n;++i){ p[i].x=p[i-1].x+a[i]-x; p[i].pos=i; tr[i]=0; } sort(p+1,p+n+1,cmp); add(p[1].pos);ll t=0; if(p[1].x<=eps)t++; for(int i=2;i<=n;++i){ if(p[i].x<=eps)t++; t+=qh(p[i].pos); add(p[i].pos); } if(t>=k)return true; return false; } int main(){ n=read();k=read();double l=1e9,r=0; for(int i=1;i<=n;++i)a[i]=read(),l=min(l,a[i]),r=max(r,a[i]); double ans=1e9; while(r-l>=eps){ double mid=(l+r)/2; if(check(mid))ans=min(ans,mid),r=mid; else l=mid; } printf("%.4lf",ans); return 0; }
题解二:实数二分+归并排序
上一种做法常数比较大,因为排序+树状数组相当于是两倍的常数。其实排序和树状数组就是为了求逆序对数,我们可以利用归并排序直接求,这样就只有一倍的常数,时间复杂度Θ(n∗(log2n)2)就可以过了。
代码2
#include <bits/stdc++.h> #define N 100005 #define ll long long #define eps 1e-5 #define min(x,y) (x<y?x:y) #define max(x,y) (x>y?x:y) using namespace std; inline int read(){ int ret=0,f=1;char tr=getchar(); for(;!isdigit(tr);tr=getchar())if(tr=='-')f=-1; for(;isdigit(tr);tr=getchar())ret=(ret<<3)+(ret<<1)+tr-'0'; return ret*f; } int n; ll k,a ,ans; double tr ,b ; inline void fz(int l,int r){ if(l==r)return ; int mid=(l+r)>>1; fz(l,mid);fz(mid+1,r); int i=l,j=mid+1,k=l-1; while(i<=mid&&j<=r){ if(b[i]<b[j])tr[++k]=b[i++]; else tr[++k]=b[j++],ans+=mid-i+1; } while(i<=mid)tr[++k]=b[i++]; while(j<=r)tr[++k]=b[j++]; for(i=l;i<=r;i++)b[i]=tr[i]; } ll check(double x){ b[0]=0; for(int i=1;i<=n;i++)b[i]=a[i]-x+b[i-1]; ans=0;fz(0,n); return ans; } int main(){ n=read();k=read();double l=1e9,r=0; for(int i=1;i<=n;++i)a[i]=read(),l=min(l,a[i]),r=max(r,a[i]); double jg=1e9; while(r-l>=eps){ double mid=(l+r)/2; if(check(mid)>=k)jg=min(jg,mid),r=mid; else l=mid; } printf("%.4lf",jg); return 0; }
相关文章推荐
- [BZOJbegin][NOIP十连测第三场]平均数(二分+归并排序求逆序对)
- 【NOIP2015模拟10.20】平均数
- [NOIP模拟][二分]能源
- [NOIP 模拟]穿越七色虹 二分答案
- 【NOIP模拟】数字对(RMQ,二分)
- 洛谷 3938 [NOIP模拟] 斐波那契 二分+找规律
- [NOIP模拟][二分]cut
- [NOIP模拟][LCS][二分][树链剖分][hdu5029]
- 【NOIP模拟考三】水资源——二分答案+Floyd验证 day1 first 信号连接
- NOIP模拟试题 软件开发(二分DP)
- 【NOIP模拟】平均数
- 【NOIp模拟】【二分答案】电缆老板
- 【NOIP 模拟赛】平均数 涂色游戏 序列题解
- 【bzoj 十连测】[noip2016十连测第三场]Problem A: 平均数(二分答案+归并排序求逆序对)
- [NOIP 模拟]疫情延迟 二分+Spfa
- 【jzoj5247】【NOIP2017提高A组模拟8.10】【计算几何】【二分答案】
- Noip 2011 选择客栈 - 模拟
- jzoj. 3453. 【NOIP2013中秋节模拟】连通块(connect)
- [NOIP2012提高]借教室 题解(二分答案+差分)
- 2067. 【2016.10.5NOIP普及模拟】zy的秘密