题目描述
跳蚤国有 nnn 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 111 号城市中。
跳蚤国最大的问题就是饮水问题,由于首都中居住的跳蚤实在太多,跳蚤国王又体恤地将分配给他的水也给跳蚤国居民饮用,这导致跳蚤国王也经常喝不上水。
于是,跳蚤国在每个城市都修建了一个圆柱形水箱,这些水箱完全相同且足够高。一个雨天后,第 iii 个城市收集到了高度为 hih_ihi 的水。由于地理和天气因素的影响,任何两个不同城市收集到的水高度互不相同。
跳蚤国王也请来蚂蚁工匠帮忙,建立了一个庞大的地下连通系统。跳蚤国王每次使用地下连通系统时,可以指定任意多的城市,将这些城市的水箱用地下连通系统连接起来足够长的时间之后,再将地下连通系统关闭。由连通器原理,这些城市的水箱中的水在这次操作后会到达同一高度,并且这一高度等于指定的各水箱高度的平均值。
由于地下连通系统的复杂性,跳蚤国王至多只能使用 kkk 次地下连通系统。
跳蚤国王请你告诉他,首都 111 号城市水箱中的水位最高能有多高?
输入格式
输入的第一行包含三个正整数 n,k,pn,k,pn,k,p 分别表示跳蚤国中城市的数量,跳蚤国王能使用地下连通系统的最多次数,以及你输出的答案要求的精度。ppp 的含义将在输出格式中解释。
接下来一行包含 nnn 个正整数,描述城市的水箱在雨后的水位。其中第 iii 个正整数 hih_ihi 表示第 iii 个城市的水箱的水位。保证 hih_ihi 互不相同,1≤hi≤1051 \leq h_i \leq 10^51≤hi≤105。
输出格式
仅一行一个实数,表示 111 号城市的水箱中的最高水位。
这个实数只可以包含非负整数部分、小数点和小数部分。其中非负整数部分为必需部分,不加正负号。若有小数部分,则非负整数部分与小数部分之间以一个小数点隔开。若无小数部分,则不加小数点。
你输出的实数在小数点后不能超过 2p2p2p 位,建议保留至少 ppp 位。数据保证参考答案与真实答案的绝对误差小于 10−2p10^{-2p}10−2p。
你的输出被判定为正确当且仅当你的输出与参考答案的绝对误差小于 10−p10^{-p}10−p。
如果你的输出与参考答案的绝对误差不小于 10−p10^{-p}10−p 但小于 10−510^{-5}10−5,你可以获得该测试点 40%40\%40% 的分数。
输入输出样例 #1
输入 #1
3 1 3
1 4 3
输出 #1
2.666667
输入输出样例 #2
输入 #2
3 2 3
1 4 3
输出 #2
3.000000
说明/提示
样例解释 1
由于至多使用一次地下连通系统,有以下五种方案:
- 不使用地下连通系统:此时 111 号城市的水箱水位为 111。
- 使用一次连通系统,连通 111、222 号:此时 111 号城市的水箱水位为 5/25/25/2。
- 使用一次连通系统,连通 111、333 号:此时 111 号城市的水箱水位为 222。
- 使用一次连通系统,连通 222、333 号:此时 111 号城市的水箱水位为 111。
- 使用一次连通系统,连通 111、222、333 号:此时 111 号城市的水箱水位为 8/38/38/3。
样例解释 2
此时最优方案为使用两次连通系统,第一次连通 1,31,31,3 号,第二次连通 1,21,21,2 号。
提示
为保证答案精度,我们一般需要尽可能地在运算过程中保留超过 ppp 位小数。我们可以证明,在各个子任务的参考算法中都能保证,在任何时候始终保留 65p\frac{6}{5}p56p 位小数时,对任何输入得到的输出,与参考答案的绝对误差都小于 10−p10^{-p}10−p。
数据范围
测试点编号 | nnn | kkk | ppp |
---|---|---|---|
1 | ≤2\le 2≤2 | ≤5\le 5≤5 | =5=5=5 |
222 | ≤4\le 4≤4 | ≤5\le 5≤5 | =5=5=5 |
333 | ≤4\le 4≤4 | ≤5\le 5≤5 | =5=5=5 |
4 | ≤10\le 10≤10 | =1=1=1 | =5=5=5 |
555 | ≤10\le 10≤10 | =109=10^9=109 | =5=5=5 |
666 | ≤10\le 10≤10 | ≤10\le 10≤10 | =5=5=5 |
777 | ≤10\le 10≤10 | ≤10\le 10≤10 | =5=5=5 |
888 | ≤100\le 100≤100 | =1=1=1 | =5=5=5 |
999 | ≤100\le 100≤100 | =109=10^9=109 | =40=40=40 |
101010 | ≤100\le 100≤100 | ≤109\le 10^9≤109 | =40=40=40 |
111111 | ≤100\le 100≤100 | ≤109\le 10^9≤109 | =40=40=40 |
121212 | ≤100\le 100≤100 | ≤109\le 10^9≤109 | =40=40=40 |
131313 | ≤250\le 250≤250 | ≤109\le 10^9≤109 | =100=100=100 |
141414 | ≤500\le 500≤500 | ≤109\le 10^9≤109 | =200=200=200 |
151515 | ≤700\le 700≤700 | ≤109\le 10^9≤109 | =300=300=300 |
161616 | ≤700\le 700≤700 | ≤109\le 10^9≤109 | =300=300=300 |
171717 | ≤700\le 700≤700 | ≤109\le 10^9≤109 | =300=300=300 |
181818 | ≤2500\le 2500≤2500 | ≤109\le 10^9≤109 | =1000=1000=1000 |
191919 | ≤4000\le 4000≤4000 | ≤109\le 10^9≤109 | =1500=1500=1500 |
202020 | ≤8000\le 8000≤8000 | ≤109\le 10^9≤109 | =3000=3000=3000 |
题解
题意简述
给定n个城市,第i个城市收集到了高度为h_i的水,要求通过使用k次地下连通系统,每次使用可以使若干个城市的水箱相连通,然后使它们的水位变为它们的平均值。要求求出k次操作后,1号城市水箱中的水位的最大值。
策略选择及最优性证明
引理0
我们一定不会对初始水位不高于1号的水箱操作。
证明:显然。
引理1.1
每次操作一定是将1与其他某些水箱连通。
证明:若某一次操作将某不含1的水箱集合S连通,用调整法证明其不优。我们取消这一次操作,在之后的操作中,设所选择的水箱集合为T,若S∩T≠∅,设S∩T=S’,则将T中在S’内的水箱替换为S中当前水位前|S’|高的水箱,容易直观理解其不劣。
引理1.2
操作与操作之间选择的除1之外的水箱一定不会有重叠。
证明:操作过的水箱与1水位相同,由引理0,可直接弃用。
引理1.3
每个除1之外的水箱都被恰好选择一次。
证明:若某水箱没有被选择过,直接在最开始将该水箱合并进1,此时可选水箱集合不变而初始水位升高,因此一定不劣。
引理2
对于初始水位高于1号的所有水箱,我们应将它们按照初始水位从小到大排序,之后按照序号从小到大进行操作,每次操作选取一段连续的区间合并到1,且全部k次操作恰好将2∼n号水箱从小到大、不重不漏地覆盖。
证明:对于相邻两次操作,设前一次操作选择的是k1个水箱,它们的值分别为a1,a2,…,ak1;后一次操作选择的是k2个水箱,它们的值分别为b1,b2,…,bk2。设操作前1号水箱的水位为x,经过这两次操作后,1号水箱的水位会变成:
f1 = (x + ∑a_i + (k1+1)∑b_i) / ((k1+1)(k2+1))
由排序不等式,这样的调整一定不劣。
动态规划解法
基本DP方程
dp[i][j] = max{dp[i-1][j], (dp[k][j-1] + sum[i] - sum[k])/(i-k+1)}
优化思路
- 状态压缩:可以去掉j维度
- 斜率优化:维护下凸壳,将复杂度从O(n²k)优化到O(nk)
代码实现
#include<bits/stdc++.h>
using namespace std;
#define LD long double
int n;
LD h1,sum[8005],h[8005],dp[8005]:ml-citation{ref="1" data="citationList"};
short from[8005][8005];
bitset<8005>jump[8005];
bool check(int k,int kn,int o,int i){
if(l==r) return true;
LD x1=k-1,y1=sum[k]-dp[o][k],x2=kn-1,y2=sum[kn]-dp[o][kn],x3=i,y3=sum[i];
return ((y2-y1)/(x2-x1))>((y3-y1)/(x3-x1));
}
int main(){
int k,p;
LD tmp;
cin>>n>>k>>p;
scanf("%Lf",&h1);
for(int i=1;i<n;i++){
scanf("%Lf",&tmp);
if(tmp>h1) h[++cnt]=tmp;
}
// ... 其余代码实现
}