题面描述
跳蚤国有(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)次的最大价值,则
观察这个式子,发现是点((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;
}