P2115 [USACO14MAR]破坏(二分答案)
2024-09-01 16:30:31
给定一串数,问删除中间一段,剩下的平均数最小是多少;
不容易想到这是个二分。
$solution:$
来手玩一点式子:
首先很容易想到一个前缀和$sum_i $表示i到1的前缀和,这样就能很容易地O(1)查询区间和/差
二分一个mid,作为最小的平均数。
假设删去区间为l~r(lr都删)
平均数等于:
$ave={sum_{i-1} + sum_{n-j} }/{n-(j-i+1)}$
于是,这里就就有了单调性:
$mid \leq ave$
稍微变形一下,就得到
$sum_n-sum_j+sum_{i-1} \leq mid*n-mid*j+mid*(i-1)$
即
$(sum_n-mid*n) \geq (sum_j-mid*j) - (sum_{i-1}-mid*(i-1) $
令$sum_i-i*mid$=$C_i$
则只需要判断
$C_n \geq C_j - C_{i-1} $
就能判断二分边界了。
复杂度$O(n)$
稍微注意下边界,就能A掉了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+;
double sum[maxn];
int n;
double c[maxn];
double maxx[maxn];
double minn[maxn];
bool check(double x)
{
for(int i=;i<=n;i++)
{
c[i]=sum[i]-i*x;
}
minn[]=c[];
for(int i=;i<=n;i++)
{
minn[i]=min(c[i],minn[i-]);
}
maxx[n-]=c[n-];
for(int i=n-;i>=;i--)
{
maxx[i]=max(c[i],maxx[i+]);
}
for(int i=;i<n;i++)
{
if(maxx[i]-minn[i-]>c[n])
return ;
}
return ;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
double x;
scanf("%lf",&x);
sum[i]=sum[i-]+x;
}
double l=,r=1e4+;
while((r-l)>0.000000001)
{
double mid=(l+r)/;
if(check(mid)==)
l=mid;
else
r=mid;
}
printf("%.3lf",l);
return ;
}
(完)
最新文章
- 循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天
- ZOJ-2342 Roads 二分图最小权值覆盖
- 使用XAMPP本地安装Wordpress博客
- FZU 2112 Tickets
- ExperDot的博客目录导航
- Java学习笔记5(类的入门以及ArrayList)
- WPF 小小案列(同步异步)
- ☆ [HNOI2012] 永无乡 「平衡树启发式合并」
- Angular MVC
- Apache Commons Digester 二(规则模块绑定-RulesModule、异步解析-asyncParse、xml变量Substitutor、带参构造方法)
- 四则运算 来源:一位热心的网友 http://www.tqcto.com/article/software/336297.html
- WebClient和WebRequest获取html代码
- [UE4]使用另一个相机Scene Capture Component 2D当小地图
- 预读(读取文件前几行)文件(txt,dat,csv等)程序
- kafka存储机制
- Solr中的一些查询参数
- day9-IO 番外
- 如何突破JAVA程序员三年的门槛
- samtools软件作用
- (4)python 字典