• LG P1721 [NOI2016]国王饮水记


    题面描述

    跳蚤国有(n)个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 (1)号城市中。
    跳蚤国最大的问题就是饮水问题,由于首都中居住的跳蚤实在太多,跳蚤国王又体恤地将分配给他的水也给跳蚤国居民饮用,这导致跳蚤国王也经常喝不上水。
    于是,跳蚤国在每个城市都修建了一个圆柱形水箱,这些水箱完全相同且足够高。一个雨天后,第(i)个城市收集到了高度为(h_i) 的水。由于地理和天气因素的影响,任何两个不同城市收集到的水高度互不相同。
    跳蚤国王也请来蚂蚁工匠帮忙,建立了一个庞大的地下连通系统。跳蚤国王每次使用地下连通系统时,可以指定任意多的城市,将这些城市的水箱用地下连通系统连接起来足够长的时间之后,再将地下连通系统关闭。由连通器原理,这些城市的水箱中的水在这次操作后会到达同一高度,并且这一高度等于指定的各水箱高度的平均值。
    由于地下连通系统的复杂性,跳蚤国王至多只能使用 (k)次地下连通系统。跳蚤国王请你告诉他,首都$ 1$号城市水箱中的水位最高能有多高?

    分析

    (1.)所有积水高度小于等于(1)号点的点可以直接丢掉. 所以,将留下来的水的高度都改成其原本的高度(-1)号点高度,最后答案再加上(1)号点的高度.

    (2.)假如被要求进行两次合并,有两杯水(h _ 1<h _ 2),则一定先合并低的,再合并高的. 证明:先合并低的:(frac{1}{2}(frac{1}{2}h_1+h _ 2)=frac{1}{4}h_1+frac{1}{2}h_2),先合并高的:(frac{1}{2}h_1+frac{1}{4}h _ 2).

    (3.)若有一部分水合并了,一部分没有,那么被合并的水一定是最高的几杯.

    将所有留下来的水从低到高排序,设(h_i)表示第(i)杯水的高度,(s _ i)表示前(i)杯水的高度前缀和.

    合并操作一定是堆在最后面的一段一段的区间,从前往后合并.

    (f(i,j))表示前j杯水合并了(i)次的最大价值,则

    [f(i,j)=maxleft{frac{f(i-1,k)+s _ j-s _ k}{j-k+1} ight} ]

    观察这个式子,发现是点((k-1,s _ k - f(i-1,k)))和点((j, s _ j))构成的直线的斜率.

    用单调队列维护点((k-1,s _ k - f(i-1,k)))构成的下凸壳.因为点((j, s _ j))(y)坐标随(x)坐标递增,所以找最优决策时,将队首一段不会构成最优决策的点的弹出,队首就是最优决策.

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<algorithm>
    
    using namespace std;
    
    const int PREC = 3000;
    
    class Decimal
    {
    	public:
    		Decimal();
    		Decimal(const std::string &s);
    		Decimal(const char *s);
    		Decimal(int x);
    		Decimal(long long x);
    		Decimal(double x);
    
    		bool is_zero() const;
    
    		std::string to_string(int p) const;
    		double to_double() const;
    
    		friend Decimal operator + (const Decimal &a, const Decimal &b);
    		friend Decimal operator + (const Decimal &a, int x);
    		friend Decimal operator + (int x, const Decimal &a);
    		friend Decimal operator + (const Decimal &a, long long x);
    		friend Decimal operator + (long long x, const Decimal &a);
    		friend Decimal operator + (const Decimal &a, double x);
    		friend Decimal operator + (double x, const Decimal &a);
    
    		friend Decimal operator - (const Decimal &a, const Decimal &b);
    		friend Decimal operator - (const Decimal &a, int x);
    		friend Decimal operator - (int x, const Decimal &a);
    		friend Decimal operator - (const Decimal &a, long long x);
    		friend Decimal operator - (long long x, const Decimal &a);
    		friend Decimal operator - (const Decimal &a, double x);
    		friend Decimal operator - (double x, const Decimal &a);
    
    		friend Decimal operator * (const Decimal &a, int x);
    		friend Decimal operator * (int x, const Decimal &a);
    
    		friend Decimal operator / (const Decimal &a, int x);
    
    		friend bool operator < (const Decimal &a, const Decimal &b);
    		friend bool operator > (const Decimal &a, const Decimal &b);
    		friend bool operator <= (const Decimal &a, const Decimal &b);
    		friend bool operator >= (const Decimal &a, const Decimal &b);
    		friend bool operator == (const Decimal &a, const Decimal &b);
    		friend bool operator != (const Decimal &a, const Decimal &b);
    
    		Decimal & operator += (int x);
    		Decimal & operator += (long long x);
    		Decimal & operator += (double x);
    		Decimal & operator += (const Decimal &b);
    
    		Decimal & operator -= (int x);
    		Decimal & operator -= (long long x);
    		Decimal & operator -= (double x);
    		Decimal & operator -= (const Decimal &b);
    
    		Decimal & operator *= (int x);
    
    		Decimal & operator /= (int x);
    
    		friend Decimal operator - (const Decimal &a);
    
    		friend Decimal operator * (const Decimal &a, double x);
    		friend Decimal operator * (double x, const Decimal &a);
    		friend Decimal operator / (const Decimal &a, double x);
    		Decimal & operator *= (double x);
    		Decimal & operator /= (double x);
    
    	private:
    		static const int len = PREC / 9 + 1;
    		static const int mo = 1000000000;
    
    		static void append_to_string(std::string &s, long long x);
    
    		bool is_neg;
    		long long integer;
    		int data[len];
    
    		void init_zero();
    		void init(const char *s);
    };
    
    Decimal::Decimal()
    {
    	this->init_zero();
    }
    
    Decimal::Decimal(const char *s)
    {
    	this->init(s);
    }
    
    Decimal::Decimal(const std::string &s)
    {
    	this->init(s.c_str());
    }
    
    Decimal::Decimal(int x)
    {
    	this->init_zero();
    
    	if (x < 0)
    	{
    		is_neg = true;
    		x = -x;
    	}
    
    	integer = x;
    }
    
    Decimal::Decimal(long long x)
    {
    	this->init_zero();
    
    	if (x < 0)
    	{
    		is_neg = true;
    		x = -x;
    	}
    
    	integer = x;
    }
    
    Decimal::Decimal(double x)
    {
    	this->init_zero();
    
    	if (x < 0)
    	{
    		is_neg = true;
    		x = -x;
    	}
    
    	integer = (long long)x;
    	x -= integer;
    
    	for (int i = 0; i < len; i++)
    	{
    		x *= mo;
    		if (x < 0) x = 0;
    		data[i] = (int)x;
    		x -= data[i];
    	}
    }
    
    void Decimal::init_zero()
    {
    	is_neg = false;
    	integer = 0;
    	memset(data, 0, len * sizeof(int));
    }
    
    bool Decimal::is_zero() const
    {
    	if (integer) return false;
    	for (int i = 0; i < len; i++)
    	{
    		if (data[i]) return false;
    	}
    	return true;
    }
    
    void Decimal::init(const char *s)
    {
    	this->init_zero();
    
    	is_neg = false;
    	integer = 0;
    
    	while (*s != 0)
    	{
    		if (*s == '-')
    		{
    			is_neg = true;
    			++s;
    			break;
    		}
    		else if (*s >= 48 && *s <= 57)
    		{
    			break;
    		}
    		++s;
    	}
    
    	while (*s >= 48 && *s <= 57)
    	{
    		integer = integer * 10 + *s - 48;
    		++s;
    	}
    
    	if (*s == '.')
    	{
    		int pos = 0;
    		int x = mo / 10;
    
    		++s;
    		while (pos < len && *s >= 48 && *s <= 57)
    		{
    			data[pos] += (*s - 48) * x;
    			++s;
    			x /= 10;
    			if (x == 0)
    			{
    				++pos;
    				x = mo / 10;
    			}
    		}
    	}
    }
    
    void Decimal::append_to_string(std::string &s, long long x)
    {
    	if (x == 0)
    	{
    		s.append(1, 48);
    		return;
    	}
    
    	char _[30];
    	int cnt = 0;
    	while (x)
    	{
    		_[cnt++] = x % 10;
    		x /= 10;
    	}
    	while (cnt--)
    	{
    		s.append(1, _[cnt] + 48);
    	}
    }
    
    std::string Decimal::to_string(int p) const
    {
    	std::string ret;
    
    	if (is_neg && !this->is_zero())
    	{
    		ret = "-";
    	}
    
    	append_to_string(ret, this->integer);
    
    	ret.append(1, '.');
    
    	for (int i = 0; i < len; i++)
    	{
    		int x = mo / 10;
    		int tmp = data[i];
    		while (x)
    		{
    			ret.append(1, 48 + tmp / x);
    			tmp %= x;
    			x /= 10;
    			if (--p == 0)
    			{
    				break;
    			}
    		}
    		if (p == 0) break;
    	}
    
    	if (p > 0)
    	{
    		ret.append(p, '0');
    	}
    
    	return ret;
    }
    
    double Decimal::to_double() const
    {
    	double ret = integer;
    
    	double k = 1.0;
    	for (int i = 0; i < len; i++)
    	{
    		k /= mo;
    		ret += k * data[i];
    	}
    
    	if (is_neg)
    	{
    		ret = -ret;
    	}
    
    	return ret;
    }
    
    bool operator < (const Decimal &a, const Decimal &b)
    {
    	if (a.is_neg != b.is_neg)
    	{
    		return a.is_neg && (!a.is_zero() || !b.is_zero());
    	}
    	else if (!a.is_neg)
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] < b.data[i];
    			}
    		}
    		return false;
    	}
    	else
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] > b.data[i];
    			}
    		}
    		return false;
    	}
    }
    
    bool operator > (const Decimal &a, const Decimal &b)
    {
    	if (a.is_neg != b.is_neg)
    	{
    		return !a.is_neg && (!a.is_zero() || !b.is_zero());
    	}
    	else if (!a.is_neg)
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] > b.data[i];
    			}
    		}
    		return false;
    	}
    	else
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] < b.data[i];
    			}
    		}
    		return false;
    	}
    }
    
    bool operator <= (const Decimal &a, const Decimal &b)
    {
    	if (a.is_neg != b.is_neg)
    	{
    		return a.is_neg || (a.is_zero() && b.is_zero());
    	}
    	else if (!a.is_neg)
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] < b.data[i];
    			}
    		}
    		return true;
    	}
    	else
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] > b.data[i];
    			}
    		}
    		return true;
    	}
    }
    
    bool operator >= (const Decimal &a, const Decimal &b)
    {
    	if (a.is_neg != b.is_neg)
    	{
    		return !a.is_neg || (a.is_zero() && b.is_zero());
    	}
    	else if (!a.is_neg)
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] > b.data[i];
    			}
    		}
    		return true;
    	}
    	else
    	{
    		if (a.integer != b.integer)
    		{
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++)
    		{
    			if (a.data[i] != b.data[i])
    			{
    				return a.data[i] < b.data[i];
    			}
    		}
    		return true;
    	}
    }
    
    bool operator == (const Decimal &a, const Decimal &b)
    {
    	if (a.is_zero() && b.is_zero()) return true;
    	if (a.is_neg != b.is_neg) return false;
    	if (a.integer != b.integer) return false;
    	for (int i = 0; i < Decimal::len; i++)
    	{
    		if (a.data[i] != b.data[i]) return false;
    	}
    	return true;
    }
    
    bool operator != (const Decimal &a, const Decimal &b)
    {
    	return !(a == b);
    }
    
    Decimal & Decimal::operator += (long long x)
    {
    	if (!is_neg)
    	{
    		if (integer + x >= 0)
    		{
    			integer += x;
    		}
    		else
    		{
    			bool last = false;
    			for (int i = len - 1; i >= 0; i--)
    			{
    				if (last || data[i])
    				{
    					data[i] = mo - data[i] - last;
    					last = true;
    				}
    				else
    				{
    					last = false;
    				}
    			}
    			integer = -x - integer - last;
    			is_neg = true;
    		}
    	}
    	else
    	{
    		if (integer - x >= 0)
    		{
    			integer -= x;
    		}
    		else
    		{
    			bool last = false;
    			for (int i = len - 1; i >= 0; i--)
    			{
    				if (last || data[i])
    				{
    					data[i] = mo - data[i] - last;
    					last = true;
    				}
    				else
    				{
    					last = false;
    				}
    			}
    			integer = x - integer - last;
    			is_neg = false;
    		}
    	}
    	return *this;
    }
    
    Decimal & Decimal::operator += (int x)
    {
    	return *this += (long long)x;
    }
    
    Decimal & Decimal::operator -= (int x)
    {
    	return *this += (long long)-x;
    }
    
    Decimal & Decimal::operator -= (long long x)
    {
    	return *this += -x;
    }
    
    Decimal & Decimal::operator /= (int x)
    {
    	if (x < 0)
    	{
    		is_neg ^= 1;
    		x = -x;
    	}
    
    	int last = integer % x;
    	integer /= x;
    
    	for (int i = 0; i < len; i++)
    	{
    		long long tmp = 1LL * last * mo + data[i];
    		data[i] = tmp / x;
    		last = tmp - 1LL * data[i] * x;
    	}
    
    	if (is_neg && integer == 0)
    	{
    		int i;
    		for (i = 0; i < len; i++)
    		{
    			if (data[i] != 0)
    			{
    				break;
    			}
    		}
    		if (i == len)
    		{
    			is_neg = false;
    		}
    	}
    
    	return *this;
    }
    
    Decimal & Decimal::operator *= (int x)
    {
    	if (x < 0)
    	{
    		is_neg ^= 1;
    		x = -x;
    	}
    	else if (x == 0)
    	{
    		init_zero();
    		return *this;
    	}
    
    	int last = 0;
    	for (int i = len - 1; i >= 0; i--)
    	{
    		long long tmp = 1LL * data[i] * x + last;
    		last = tmp / mo;
    		data[i] = tmp - 1LL * last * mo;
    	}
    	integer = integer * x + last;
    
    	return *this;
    }
    
    Decimal operator - (const Decimal &a)
    {
    	Decimal ret = a;
    	if (!ret.is_neg && ret.integer == 0)
    	{
    		int i;
    		for (i = 0; i < Decimal::len; i++)
    		{
    			if (ret.data[i] != 0) break;
    		}
    		if (i < Decimal::len)
    		{
    			ret.is_neg = true;
    		}
    	}
    	else
    	{
    		ret.is_neg ^= 1;
    	}
    	return ret;
    }
    
    Decimal operator + (const Decimal &a, int x)
    {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator + (int x, const Decimal &a)
    {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator + (const Decimal &a, long long x)
    {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator + (long long x, const Decimal &a)
    {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator - (const Decimal &a, int x)
    {
    	Decimal ret = a;
    	return ret -= x;
    }
    
    Decimal operator - (int x, const Decimal &a)
    {
    	return -(a - x);
    }
    
    Decimal operator - (const Decimal &a, long long x)
    {
    	Decimal ret = a;
    	return ret -= x;
    }
    
    Decimal operator - (long long x, const Decimal &a)
    {
    	return -(a - x);
    }
    
    Decimal operator * (const Decimal &a, int x)
    {
    	Decimal ret = a;
    	return ret *= x;
    }
    
    Decimal operator * (int x, const Decimal &a)
    {
    	Decimal ret = a;
    	return ret *= x;
    }
    
    Decimal operator / (const Decimal &a, int x)
    {
    	Decimal ret = a;
    	return ret /= x;
    }
    
    Decimal operator + (const Decimal &a, const Decimal &b)
    {
    	if (a.is_neg == b.is_neg)
    	{
    		Decimal ret = a;
    		bool last = false;
    		for (int i = Decimal::len - 1; i >= 0; i--)
    		{
    			ret.data[i] += b.data[i] + last;
    			if (ret.data[i] >= Decimal::mo)
    			{
    				ret.data[i] -= Decimal::mo;
    				last = true;
    			}
    			else
    			{
    				last = false;
    			}
    		}
    		ret.integer += b.integer + last;
    		return ret;
    	}
    	else if (!a.is_neg)
    	{
    		return a - -b;
    	}
    	else
    	{
    		return b - -a;
    	}
    }
    
    Decimal operator - (const Decimal &a, const Decimal &b)
    {
    	if (!a.is_neg && !b.is_neg)
    	{
    		if (a >= b)
    		{
    			Decimal ret = a;
    			bool last = false;
    			for (int i = Decimal::len - 1; i >= 0; i--)
    			{
    				ret.data[i] -= b.data[i] + last;
    				if (ret.data[i] < 0)
    				{
    					ret.data[i] += Decimal::mo;
    					last = true;
    				}
    				else
    				{
    					last = false;
    				}
    			}
    			ret.integer -= b.integer + last;
    			return ret;
    		}
    		else
    		{
    			Decimal ret = b;
    			bool last = false;
    			for (int i = Decimal::len - 1; i >= 0; i--)
    			{
    				ret.data[i] -= a.data[i] + last;
    				if (ret.data[i] < 0)
    				{
    					ret.data[i] += Decimal::mo;
    					last = true;
    				}
    				else
    				{
    					last = false;
    				}
    			}
    			ret.integer -= a.integer + last;
    			ret.is_neg = true;
    			return ret;
    		}
    	}
    	else if (a.is_neg && b.is_neg)
    	{
    		return -b - -a;
    	}
    	else if (a.is_neg)
    	{
    		return -(-a + b);
    	}
    	else
    	{
    		return a + -b;
    	}
    }
    
    Decimal operator + (const Decimal &a, double x)
    {
    	return a + Decimal(x);
    }
    
    Decimal operator + (double x, const Decimal &a)
    {
    	return Decimal(x) + a;
    }
    
    Decimal operator - (const Decimal &a, double x)
    {
    	return a - Decimal(x);
    }
    
    Decimal operator - (double x, const Decimal &a)
    {
    	return Decimal(x) - a;
    }
    
    Decimal & Decimal::operator += (double x)
    {
    	*this = *this + Decimal(x);
    	return *this;
    }
    
    Decimal & Decimal::operator -= (double x)
    {
    	*this = *this - Decimal(x);
    	return *this;
    }
    
    Decimal & Decimal::operator += (const Decimal &b)
    {
    	*this = *this + b;
    	return *this;
    }
    
    Decimal & Decimal::operator -= (const Decimal &b)
    {
    	*this = *this - b;
    	return *this;
    }
    
    /*以上为高精度浮点数模板*/
    
    const int Maxn=8007;
    
    inline int input()
    {
    	register int x=0,c=getchar(),s=1;
    	
    	while(c<'0'||c>'9')
    		(c=='-')&&(s=-1),
    		c=getchar();
    	
    	while(c>='0'&&c<='9')
    		x=(x<<1)+(x<<3)+(c^48),
    		c=getchar();
    	
    	return c*s;
    }
    
    
    Decimal ans;
    
    int n,K,p,h[Maxn],zy[Maxn][15],s[Maxn],tot;
    int Q[Maxn],H,T;
    double f[Maxn][15];
    
    struct Point
    {
    	double x,y;
    }q[Maxn];
    
    inline double slope(Point a,Point b)
    {
    	return (a.y-b.y)/(a.x-b.x);
    }
    
    inline Decimal calc(int i,int j)
    {
    	if(!j)
    		return h[1];
    		
    	return (calc(zy[i][j],j-1)+s[i]-s[zy[i][j]])/(i-zy[i][j]+1);
    }
    int main()
    {
    	n=input();
    	K=input();
    	p=input();
    	h[tot=1]=input();
    	
    	for(int i=2;i<=n;++i)
    	{
    		h[i]=input();
    		
    		if(h[i]>h[1])
    			h[++tot]=h[i];
    	}
    	
    	n=tot;
    	sort(&h[1],&h[n+1]);
    	
    	for(int i=1;i<=n;++i)
    		s[i]=s[i-1]+h[i];
    		
    	K=min(K,n);
    	
    	for(int i=1;i<=n;++i)
    		f[i][0]=h[1];
    		
    	int lim=min(K,14);
    	
    	for(int j=1;j<=lim;++j)
    	{
    		Q[H=T=1]=1;
    		
    		for(int i=1;i<=n;++i)
    			q[i]=(Point)
    			{
    				i-1,s[i]-f[i][j-1]
    			};
    			
    		for(int i=2;i<=n;++i)
    		{
    			Point u=(Point)
    			{
    				i,s[i]
    			};
    			
    			while(H<T&&slope(u,q[Q[H]])<slope(u,q[Q[H+1]]))
    				++H;
    			
    			zy[i][j]=Q[H];
    			f[i][j]=(s[i]-s[Q[H]]+f[Q[H]][j-1])/(i-Q[H]+1);
    			
    			while(H<T&&slope(q[Q[T]],q[Q[T-1]])>slope(q[Q[T]],q[i]))
    				--T;
    				
    			Q[++T]=i;
    		}
    	}
    	int m=n-K+lim,pos;
    	double mx=0;
    	
    	for(int j=0;j<=lim;++j)
    		if(f[m][j]>mx)
    			mx=f[m][j],
    			pos=j;
    			
    	ans=calc(m,pos);
    	
    	for(int i=m+1;i<=n;++i)
    		ans=(ans+h[i])/2;
    		
    	cout<<ans.to_string(p<<1)<<endl;
    }
    
  • 相关阅读:
    一个合格的程序员应该读过哪些书
    一个程序员如何快速赚到一百万?
    如何创造财富?硅谷创业之父 Paul Graham 《黑客与画家》思维导图
    java 入门书籍(java7)
    活动预售和预热的目的
    活动策划
    店铺费率把控
    如何通过店铺数据分析店铺异常原因?
    刷单三大目的?如何安全、低成本、高效完成刷单
    活动报名技巧之——天天特卖
  • 原文地址:https://www.cnblogs.com/Anverking/p/solution-lgp1721.html
Copyright © 2020-2023  润新知