[NOIP2017模拟]最佳序列
来源:互联网 发布:灯火阑珊网络电视直播 编辑:程序博客网 时间:2024/06/01 07:12
2017.11.2 T2 2029
样例数据
输入
3 2 3
6 2 8
输出
5.3333
分析:这道题我只会扫描所有的区间输出答案这种暴力,也就是说复杂度是O(
正解是单调队列优化:
二分平均数,将每个数都减去一个平均数,然后记录前缀和,如果在长为l到r的所有区间中有前缀和大于0的说明就可以到这个平均数,没有就说明不能到平均数,单调队列能让这个过程变成O(
代码
100%:暴力+优化
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;inline int getint(){ int sum=0,f=1; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) sum=(sum<<3)+(sum<<1)+ch-48; return sum*f;}const int maxn=20005;const double eps=1e-9;int n,l,r,a[maxn],maxa;double ans,sum[maxn];inline void solve(){ for(register int i=l;i<=min(l*2,r);++i)//这是个优化//如果是一个数的区间,显然取最大的那个数就行,它和任意数取平均数都会比本身小//同理,如果找到了长为l的平均最大的区间,显然与其他长为l的区间合并求平均数都会比他小,所以只需要求长为l到长为2l的区间的最大值就完了//现在想来觉得有点小bug啊...... { if(sum[i]/i-ans>eps) ans=sum[i]/i; for(register int j=i+1;j<=n;++j) if((sum[j]-sum[j-i])/i-ans>eps) ans=(sum[j]-sum[j-i])/i; } printf("%0.4f\n",ans);}int main(){ freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); n=getint(),l=getint(),r=getint(); for(register int i=1;i<=n;++i) { a[i]=getint(); sum[i]=sum[i-1]+a[i];//记录前缀和 } solve(); return 0;}
100%:单调队列优化
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<deque>#include<set>using namespace std;int getint(){ int sum=0,f=1; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) sum=(sum<<3)+(sum<<1)+ch-48; return sum*f;}const int maxn=20010;const double eps=1e-9;int n,l,r;double w,ans,a[maxn],maxa,b[maxn],sum[maxn];bool check(double x){ for(int i=1;i<=n;++i) b[i]=a[i]-x;//把所有的数减去二分的这个平均数 for(int i=1;i<=n;++i) sum[i]=sum[i-1]+b[i];//记录前缀和 deque<int> que; for(int i=l;i<=r-1;++i)//先把长为l到r-1的前缀和放到数组里(只能是单调队列,小于的都删掉) { while(!que.empty()&&sum[i]>sum[que.back()]) que.pop_back(); que.push_back(i); } for(int i=1;i<=n-l+1;++i)//固定左端点 { while(!que.empty()&&que.front()<i+l-1) que.pop_front();//删除队顶与左端点相距小于的l的点(可能队列中还有,但是单调队列只关注最大的),保证队顶的数是满足在左端点右侧l到r的距离内的 if(i+r-1<=n) { while(!que.empty()&&sum[i+r-1]>sum[que.back()])//加入新的,把小于它的都删掉 que.pop_back(); que.push_back(i+r-1); } if(sum[que.front()]-sum[i-1]>=0)//判断队列中(队列中的都是满足在区间里的)最大的能否让前缀和大于0,满足了就return true return true; } return false;}int main(){ freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); n=getint(),l=getint(),r=getint(); for(int i=1;i<=n;++i) { scanf("%lf",&a[i]); if(a[i]-maxa>eps) maxa=a[i]; } double l=0,r=maxa,mid; while(r-l>eps)//二分查找平均数 { mid=(l+r)/2; if(check(mid)) l=mid,ans=mid; else r=mid; } printf("%0.4f\n",ans); return 0;}
本题结。
阅读全文
0 0
- [NOIP2017模拟]最佳序列
- [NOIP2017模拟]序列操作
- 【jzoj5231】【NOIP2017模拟A组模拟8.5】【序列问题】 【分治】
- 【NOIP2017模拟A组模拟8.5】序列问题
- 高中OJ5231. 【NOIP2017模拟A组模拟8.5】序列问题
- 【JZOJ5231】【NOIP2017模拟A组模拟8.5】序列问题
- 【NOIP2017模拟A组模拟8.5】序列问题
- NOIP模拟(11.02)T2 最佳序列
- 【NOIP模拟】 (11.2) T2最佳序列
- NOIP模拟(20171102)T2 最佳序列
- NOIP模拟:最佳序列(单调队列DP)
- NOIP2017模拟赛1
- NOIP2017模拟赛8
- NOIP2017模拟赛9
- [NOIP2017模拟]切蛋糕
- [NOIP2017模拟]随机图
- [NOIP2017模拟]能源
- [NOIP2017模拟]电影
- HDU-2007(平方和与立方和)
- 代码行数统计器
- 习题5.1
- git常用命令整理
- Linux基础操作-2.常用命令
- [NOIP2017模拟]最佳序列
- 日常运维(八):sync通过服务同步,linux系统日志,screen工具
- Linux基础部分-2.文件相关命令
- Junit4如何正确测试异常
- Google超有趣小实验合集 | 不论你会不会编程,你都可以在这感受到AI的乐趣
- NOIP模拟 JZOI5428 查询 【链表】
- (转)区块链原理最清晰最直观的解释
- 成绩排序
- uORB通信机制和添加自己的topics学习笔记