zoukankan      html  css  js  c++  java
  • HDU 2993 MAX Average Problem

    在这里插入图片描述
    这题要卡读入,必须用fread。
    以下提供两种方法:
    1.

    //二分做法,时间复杂度O(T*N*log20000000),T为数据组数。超时代码——HDU数据真强。
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+10;
    const double eps=1e-4;
    int n,m,a[N];
    double s[N],l,r,mid;
    bool check(double c)
    {
    	for(int i=1;i<=n;i++)
    		s[i]=s[i-1]+a[i]-c;
    	double minn=0;
    	for(int i=m;i<=n;i++)
    	{
    		minn=min(s[i-m],minn);
    		if(s[i]-minn>=0)return 1;
    	}
    	return 0;
    }
    #define g getchar()
    void qr(int &x)
    {
    	char c=g;x=0;
    	while(!('0'<=c&&c<='9'))c=g;
    	while('0'<=c&&c<='9')x=x*10+c-'0',c=g;
    }
    int main()
    {
    	while(~scanf("%d%d",&n,&m))
    	{
    		l=2000;r=1;
    		for(int i=1;i<=n;i++)qr(a[i]),l=min(l,(double)a[i]),r=max(r,(double)a[i]);
    		while(l<r-eps)
    		{
    			mid=(l+r)/2;
    			if(check(mid))l=mid;
    			else r=mid;
    		}
    		printf("%.2lf
    ",r);
    	}
    	return 0;
    }
    		
    
    

    斜率优化。
    解题思路(转自《浅谈数形结合思想在信息学竞赛中的应用》—周源):
    首先一定会设序列ai的部分和:Si=a1+a2+…+ai,,特别的定义S0=0。
    这样可以很简洁的表示出目标函数ave(i,j)=(Sj-S(i-1))/(j-(i-1))!
    如果将S函数绘在平面直角坐标系内,这就是过点Sj和点Si-1直线的斜率!
    于是问题转化为:平面上已知N+1 个点,Pi(i, Si),0≤i≤N,求横向距离大
    于等于F的任意两点连线的最大斜率。

    构造下凸折线
    有序化一下,规定对i<j,只检查Pj向Pi的连线,对Pi不检查与Pj的连线。
    也就是说对任意一点,仅检查该点与在其前方的点的斜率。于是我们定义点Pi
    的检查集合为
    Gi = {Pj, 0≤j≤i-F}
    特别的,当i<F时,Gi为空集。
    其明确的物理意义为:在平方级算法中,若要检查ave(a, b),那么一定有Pa∈Gb;
    因此平方级的算法也可以这样描述,首先依次枚举Pb点,再枚举Pa∈Gb,同时检查k(PaPb)。//k为斜率

    若将Pi和Gi同时列出,则不妨称Pi为检查点,Gi中的元素都是Pi的被检查点。
    当我们考察一个点Pt时,朴素的平方级算法依次选取Gt中的每一个被检查点p,
    考察直线pPt的斜率。但仔细观察,若集合内存在三个点Pi, Pj, Pk,且i<j<k,三个点形成如下图
    所示的的关系,即Pj点在直线PiPk的上凸部分:k(Pi, Pj)>k(Pj,Pk),就很容易可以证明Pj点是多余的。
    在这里插入图片描述

    若k(Pt, Pj) > k(Pt, Pi),那么可以看出,Pt点一定要在直线PiPj的上方,即阴
    影所示的1号区域。同理若k(Pt, Pj) > k(Pt, Pk),那么Pt点一定要在直线PjPk的下
    方,即阴影所示的2号区域。

    综合上述两种情况,若PtPj的斜率同时大于PtPi和PtPk的,Pt点一定要落在两阴影的重叠部分,
    但这部分显然不满足开始时t>j 的假设。于是,Pt落在任何一个合法的位置时,PtPj的斜率要么小于PtPi,
    要么小于PtPk,即不可能成为最大值,因此Pj点多余,完全可以从检查集合中删去。这个结论告诉我们,
    任何一个点Pt的检查集合中,不可能存在一个对最优结果有贡献的上凸点,因此我们可以删去每一个上凸点,
    剩下的则是一个下凸折线。最后需要在这个下凸折线上找一点与Pt 点构成的直线斜率最大——显然这条直
    线是在与折线相切时斜率最大,如图所示。
    在这里插入图片描述

    维护下凸折线
    这一小节中,我们的目标是:用尽可能少的时间得到每一个检查点的下凸折线。
    算法首先从PF开始执行:它是检查集合非空的最左边的一个点,集合内仅有一个元素P0,
    而这显然满足下凸折线的要求,接着向右不停的检查新的点:PF+1,PF+2, …, PN。

    检查的过程中,维护这个下凸折线:每检查一个新的点Pt,就可以向折线最右端加入一个新的点Pt-F,
    同时新点的加入可能会导致折线右端的一些点变成上凸点,我们用一个类似于构造凸包的过程依次删去这些上凸点,
    从而保证折线的下凸性。由于每个点仅被加入和删除一次,所以每次维护下凸折线的平摊复杂度为O(1),
    即我们用O(N)的时间得到了每个检查集合的下凸折线。

    最后的优化:利用图形的单调性
    最后一个问题就是如何求过Pt点,且与折线相切的直线了。一种直接的方法就是二分,每次查找的复杂度是O(log2N)O(log_2N)
    但是从图形的性质上很容易得到另一种更简便更迅速的方法:
    由于折线上过每一个点切线的斜率都是一定的,而且根据下凸函数斜率的单调性,如果在检查点Pt 时找到了折线上的已知一个切点A,
    那么A以前的所有点都可以删除了:过这些点的切线斜率一定小于已知最优解,这些点不会做出更大的贡献了。
    于是另外保留一个指针不回溯的向后移动以寻找切线斜率即可,平摊复杂度为为O(1)。
    至此,此题算法时空复杂度均为O(N),得到了圆满的解决。

    本人代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+10;
    const int size=1<<20;
    inline char g()
    {
    	static char buf[size],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++;
    }
    #define g g()
    void qr(int &x)
    {
    	char c=g;x=0;if(c==EOF)return;
    	while(!('0'<=c&&c<='9'))c=g;
    	while('0'<=c&&c<='9')x=x*10+c-'0',c=g;
    }
    int s[N],n,m,q[N],l,r;
    double slope(int i,int j)
    {
    	return (double)(s[i]-s[j])/(i-j);
    }
    int main()
    {
    	while(qr(n),n)
    	{
    		qr(m);
    		for(int i=1;i<=n;i++)
    			qr(s[i]),s[i]=s[i]+s[i-1];
    		l=1;r=0;double ans=0;
    		for(int i=m;i<=n;i++)
    		{
    			while(l<r&&slope(q[r-1],q[r])>=slope(q[r],i-m))r--;
    			q[++r]=i-m;
    			while(l<r&&slope(q[l],i)<=slope(q[l+1],i))l++;
    			ans=max(ans,slope(q[l],i));
    		}
    		printf("%.2lf
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    jQuery知识点小结
    Java并发(二):基础概念
    Java并发(一):基础概念
    Spring AOP初步总结(二)
    pycharm建立软连接
    python中安装pycurl(想要使用Tornado提供的客户端做爬虫 客户端里需要先安装pycurl)
    python2&python3 蛋疼的编码问题
    02-Elasticsearch的核心概念
    python-列表或元组去重
    python-enumerate函数
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373912.html
Copyright © 2011-2022 走看看