test 3 Problem A: [noip2016十连测第三场]平均数 (实数二分+排序+树状数组)
2016-11-16 16:59
369 查看
Problem A: [noip2016十连测第三场]平均数
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 158 Solved: 49
[Submit][Status][Web
Board]
Description
有一天,小A得到了一个长度为n的序列。他把这个序列的所有连续子序列都列了出来,并对每一个子序列都求了其平均值,然后他把这些平均值写在纸上,并对它们进行排序,最后他报出了第k小的平均值。你要做的就是模仿他
的过程。
Input
第一行两个整数n,k,意义如题中所述。第二行n个正整数,即为小A得到的序列。
Output
一行一个实数,表示第k小的平均值,保留到小数点后4位。【 数据范围与约定】
对于 40%的数据, n≤1000
对于 100%的数据, n≤100000, k≤n*(n+1)/2, 序列中的数≤10^9
Sample Input
<span class="sampledata">6 10 3 5 4 6 1 2</span>
Sample Output
<span class="sampledata">3.6667</span>
HINT
[Submit][Status]题解:实数二分+树状数组+排序。
先分析一下题目,如果是暴利枚举的话肯定会TLE。所以我们只能考虑二分答案,我们二分到一个平均数,如何判断他是否可行呢?加上当前的平均数为x,那么我们对于每一个数都减去x,对于每一个位置求前缀和,然后将得到的前缀和排序。通过前缀和作差我们是可以得到一段区间的总和的,我们要求平均数<=x的子序列个数,那么在所有数减去x的情况下就是求有多少区间的和是<=esp(精度误差),那么我们将前缀和按照从大到小排序,当前位置之前有多少在数列中位置小于当前位置的数就是对答案的贡献,可以用树状数组来统计答案。但是这样做在不开O2的情况下会TLE。
[cpp] view
plain copy
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
#define esp 1e-7
#define LL long long
using namespace std;
int n;
LL m,tr
;
double b
,a
,maxn,minn,l,r;
struct data
{
double x;
int pos;
}sum
;
int cmp(data a,data b)
{
return a.x-b.x>esp||a.x-b.x<=esp&&a.x-b.x>=-esp&&a.pos<b.pos;
}
int lowbit(int x)
{
return x&(-x);
}
void change(int x)
{
for (int i=x;i<=n;i+=lowbit(i))
tr[i]++;
}
LL sum1(int x)
{
LL ans=0;
for (int i=x;i>=1;i-=lowbit(i))
ans+=tr[i];
return ans;
}
bool pd(double x)
{
sum[0].x=0; sum[0].pos=0;
for (int i=1;i<=n;i++) sum[i].x=sum[i-1].x+a[i]-x,sum[i].pos=i,tr[i]=0;
sort(sum+1,sum+n+1,cmp);
change(sum[1].pos); LL t=0;
if (sum[1].x<=esp) t++;
for (int i=2;i<=n;i++)
{
if (sum[i].x<=esp) t++;
t+=sum1(sum[i].pos);
change(sum[i].pos);
}
if (t>=m) return true;
return false;
}
int main()
{
freopen("a.in","r",stdin);
//freopen("my.out","w",stdout);
scanf("%d%I64d",&n,&m); l=1e9;
for (int i=1;i<=n;i++) scanf("%lf",&a[i]),r=max(r,a[i]),l=min(l,a[i]);
double ans=1e9;
while (r-l>=esp)
{
double mid=(l+r)/2;
if (pd(mid)) ans=min(ans,mid),r=mid;
else l=mid;
}
printf("%.4lf\n",ans);
}
题解:实数二分+归并排序
上一种做法常数比较大,因为排序+树状数组相当于是两倍的常数。
其实排序和树状数组就是为了求逆序对数,我们可以利用归并排序直接求,这样就只有一倍的常数,就可以过了。
[cpp] view
plain copy
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef double db;
typedef long long ll;
const int N=100010;
const db eps=1e-6;
db b
,c
;
int a
;
ll ans=0;
int n;
void solve(int l,int r){
if(l==r) return;
int M=l+r>>1;
solve(l,M);solve(M+1,r);
int i=l,j=M+1,k=l-1;
while(i<=M&&j<=r){
if(b[i]<b[j]) c[++k]=b[i++];
else c[++k]=b[j++],ans+=M-i+1;
}
while(i<=M) c[++k]=b[i++];
while(j<=r) c[++k]=b[j++];
for(i=l;i<=r;i++) b[i]=c[i];
}
ll calc(db x){
b[0]=0;
for(int i=1;i<=n;i++) b[i]=a[i]-x+b[i-1];
ans=0;
solve(0,n);
return ans;
}
int main(){
freopen("ave.in","r",stdin);
freopen("ave.out","w",stdout);
int mx=0,i;
db lb,rb,mid;
ll x;
scanf("%d %lld",&n,&x);
for(i=1;i<=n;i++) scanf("%d",&a[i]),mx=max(mx,a[i]);
lb=0;rb=mx;
while(rb-lb>eps){
mid=(lb+rb)/2;
if(calc(mid)<x) lb=mid;
else rb=mid;
}
printf("%.4lf\n",lb);
return 0;
}
相关文章推荐
- test3 Problem C: [noip2016十连测第三场]序列 (主席树)
- 【bzoj 十连测】[noip2016十连测第三场]Problem A: 平均数(二分答案+归并排序求逆序对)
- test 8 Problem A: [noip2016十连测第八场]神炎皇 (数论+gcd两个性质的证明)
- 【bzoj 十连测】[noip2016十连测第三场]Problem C: 序列(静态主席树)
- test 8 Problem C: [noip2016十连测第八场]幻魔皇 (递推+乱搞)
- test 8 Problem B: [noip2016十连测第八场]降雷皇 (dp+线段树)
- test 7 Problem A: [noip2016十连测第七场]约瑟夫游戏 (找规律+数论)
- nefu 84 http://acm.nefu.edu.cn/test/problemshow.php?problem_id=84
- Problem B: [noip2016十连测第五场]walk (树形dp)
- 【bzoj 十连测】[noip2016十连测第七场]Problem A: 约瑟夫游戏(递推+打表)
- 多校第三场 1006 hdu 5323 Solve this interesting problem(dfs)
- Round A China New Grad Test 2014 Problem C. Sorting
- Google APAC test 2015 Round B Problem D-Parentheses Order
- Ubuntu 16.04出现:Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/
- Ubuntu 16.04出现:Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/
- nefu 84 http://acm.nefu.edu.cn/test/problemshow.php?problem_id=84
- Problem A: [noip2016十连测第五场]simple(模拟)
- 【bzoj 十连测】[noip2016十连测第八场]Problem B: 降雷皇(最长上升子序列+线段树|next数组)
- Problem C. Not So Random Google APAC 2017 University Test Practice Round
- Round A APAC Test 2016 Problem C. gCampus 最短路