LOJ#2087 国王饮水记

解:这个题一脸不可做...
比1小的怎么办啊,好像没用,扔了吧。
先看部分分,n = 2简单,我会分类讨论!n = 4简单,我会搜索!n = 10,我会剪枝!
k = 1怎么办,好像选的那些越大越好啊,那么我就排序之后枚举后缀!
k = INF怎么办啊,好像最优策略是从小到大一个一个连通啊,那直接模拟好了。
写一写,有40分了。
别的怎么办啊,拿搜索找规律吧?于是发现一个规律(伪):最优策略一定是单独选择最后k - 1个,和前面的一个后缀。
于是枚举后缀,然后模拟后面的部分,成功得到了61分!
#include <bits/stdc++.h> // ---------- decimal lib start ---------- // ---------- decimal lib end ---------- const int N = ; int n, k, p;
Decimal a[N]; inline void output(Decimal x) {
std::cout << x.to_string(p + ) << std::endl;
return;
} inline void output(double x) {
printf("%.10f\n", x);
return;
} inline void out(int x) {
for(int i = ; i < n; i++) {
printf("%d", (x >> i) & );
}
return;
} namespace bf { const double eps = 1e-; double ans = , a[N], temp[][];
int lm, pw[], Ans[N], now[N]; void DFS(int x) {
/// check
double large();
for(int i = ; i <= n; i++) {
if(large < a[i]) large = a[i];
}
if(large < ans + eps) {
return;
}
if(fabs(large - a[]) < eps || x > k) {
if(ans < a[]) {
ans = a[];
memcpy(Ans + , now + , x * sizeof(int));
}
return;
} for(int i = ; i <= n; i++) {
temp[x - ][i] = a[i];
}
for(int s = lm - ; s > ; s--) {
if(!(s - (s & (-s)))) continue;
double tot = ;
int cnt = ;
int t = s;
while(t) {
int tt = pw[t & (-t)] + ;
tot += a[tt];
cnt++;
t ^= << (tt - );
}
tot /= cnt;
t = s;
while(t) {
int tt = pw[t & (-t)] + ;
a[tt] = tot;
t ^= << (tt - );
}
now[x] = s;
DFS(x + );
t = s;
while(t) {
int tt = pw[t & (-t)] + ;
a[tt] = temp[x - ][tt];
t ^= << (tt - );
}
}
now[x] = ;
return;
} inline void solve() { /// DFS
lm = << n;
for(int i = ; i < n; i++) {
pw[ << i] = i;
}
for(int i = ; i <= n; i++) {
a[i] = ::a[i].to_double();
}
DFS(); output(ans); /*for(int i = 1; i <= k + 1; i++) {
out(Ans[i]); printf(" ");
}
puts("");*/
return;
}
} int main() { //freopen("in.in", "r", stdin); scanf("%d%d%d", &n, &k, &p);
for(int i = , x; i <= n; i++) {
scanf("%d", &x);
a[i] = x;
} std::sort(a + , a + n + );
if(n == ) {
output(a[]);
return ;
}
if(n == ) {
if(a[] > a[]) {
output(a[]);
}
else {
a[] = (a[] + a[]) / ;
output(a[]);
}
return ;
}
if(a[] >= a[n]) {
output(a[]);
return ;
}
if(k == ) {
Decimal tot = a[], ans = a[];
int cnt = ;
for(int i = n; i >= ; i--) {
cnt++;
tot += a[i];
ans = std::max(ans, tot / cnt);
}
output(ans);
return ;
}
if(k >= n - ) {
for(int i = ; i <= n; i++) {
if(a[] > a[i]) continue;
a[] = (a[] + a[i]) / ;
}
output(a[]);
return ;
}
if(n <= ) {
bf::solve();
return ;
}
else {
Decimal tot = a[], ans = a[];
int cnt = ;
for(int i = n - k + ; i >= ; i--) {
cnt++;
tot += a[i];
ans = std::max(ans, tot / cnt);
}
a[] = ans;
for(int i = n - k + ; i <= n; i++) {
if(a[] > a[i]) continue;
a[] = (a[] + a[i]) / ;
}
output(a[]);
return ;
}
return ;
}
61分代码
正确的规律:最优策略一定是把一个后缀分成连续若干段。
于是以此DP,设f[i][j]表示前i次操作取到了j,此时1号点的最大值。转移就枚举从哪来即可。注意初始化。
#include <bits/stdc++.h> // ---------- decimal lib start ---------- const int PREC = ; // ---------- decimal lib end ---------- const int N = ; int n, k, p;
Decimal a[N]; inline void output(Decimal x) {
std::cout << x.to_string(p + ) << std::endl;
return;
} inline void output(double x) {
printf("%.10f\n", x);
return;
} inline void out(int x) {
for(int i = ; i < n; i++) {
printf("%d", (x >> i) & );
}
return;
} namespace bf { const double eps = 1e-; double ans = , a[N], temp[][];
int lm, pw[], Ans[N], now[N]; void DFS(int x) {
/// check
double large();
for(int i = ; i <= n; i++) {
if(large < a[i]) large = a[i];
}
if(large < ans + eps) {
return;
}
if(fabs(large - a[]) < eps || x > k) {
if(ans < a[]) {
ans = a[];
memcpy(Ans + , now + , x * sizeof(int));
}
return;
} for(int i = ; i <= n; i++) {
temp[x - ][i] = a[i];
}
for(int s = lm - ; s > ; s--) {
if(!(s - (s & (-s)))) continue;
double tot = ;
int cnt = ;
int t = s;
while(t) {
int tt = pw[t & (-t)] + ;
tot += a[tt];
cnt++;
t ^= << (tt - );
}
tot /= cnt;
t = s;
while(t) {
int tt = pw[t & (-t)] + ;
a[tt] = tot;
t ^= << (tt - );
}
now[x] = s;
DFS(x + );
t = s;
while(t) {
int tt = pw[t & (-t)] + ;
a[tt] = temp[x - ][tt];
t ^= << (tt - );
}
}
now[x] = ;
return;
} inline void solve() { /// DFS
lm = << n;
for(int i = ; i < n; i++) {
pw[ << i] = i;
}
for(int i = ; i <= n; i++) {
a[i] = ::a[i].to_double();
}
DFS(); output(ans); /*for(int i = 1; i <= k + 1; i++) {
out(Ans[i]); printf(" ");
}
puts("");*/
return;
}
} Decimal f[][];
int sum[N]; inline void solve() {
int I = ;
while(a[] > a[I]) ++I;
for(int i = ; i <= n; i++) {
f[][i] = a[];
}
for(int i = ; i <= k; i++) {
f[i][I - ] = a[];
for(int j = I; j <= n; j++) {
/// f[i][j]
f[i][j] = f[i - ][j];
for(int p = I - ; p < j; p++) {
Decimal t = (f[i - ][p] + sum[j] - sum[p]) / (j - p + );
if(f[i][j] < t) {
f[i][j] = t;
}
}
//printf("i = %d j = %d f = ", i, j); output(f[i][j]);
}
}
output(f[k][n]);
return;
} int main() { //freopen("in.in", "r", stdin);
//printf("%d \n", (sizeof(f)) / 1048576); scanf("%d%d%d", &n, &k, &p);
for(int i = , x; i <= n; i++) {
scanf("%d", &x);
a[i] = x;
} std::sort(a + , a + n + );
for(int i = ; i <= n; i++) {
sum[i] = sum[i - ] + (int)(a[i].to_double() + 0.5);
}
if(n == ) {
output(a[]);
return ;
}
if(n == ) {
if(a[] > a[]) {
output(a[]);
}
else {
a[] = (a[] + a[]) / ;
output(a[]);
}
return ;
}
if(a[] >= a[n]) {
output(a[]);
return ;
}
if(k == ) {
Decimal tot = a[], ans = a[];
int cnt = ;
for(int i = n; i >= ; i--) {
cnt++;
tot += a[i];
ans = std::max(ans, tot / cnt);
}
output(ans);
return ;
}
if(k >= n - ) {
for(int i = ; i <= n; i++) {
if(a[] > a[i]) continue;
a[] = (a[] + a[i]) / ;
}
output(a[]);
return ;
}
if(n <= ) {
bf::solve();
return ;
}
else {
solve();
return ;
}
return ;
}
60分代码
考虑如何优化这个DP。
LOJ#2087 国王饮水记的更多相关文章
- 【BZOJ4654】【NOI2016】国王饮水记(动态规划,斜率优化)
[BZOJ4654][NOI2016]国王饮水记(动态规划,斜率优化) 题面 BZOJ 洛谷 题解 首先肯定是找性质. 明确一点,比\(h_1\)小的没有任何意义. 所以我们按照\(h\)排序,那么\ ...
- [UOJ#223][BZOJ4654][Noi2016]国王饮水记
[UOJ#223][BZOJ4654][Noi2016]国王饮水记 试题描述 跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1 号城市中.跳蚤国最大的问题就是饮水问题,由于首都中居住的跳 ...
- luogu P1721 [NOI2016]国王饮水记 斜率优化dp 贪心 决策单调性
LINK:国王饮水记 看起来很不可做的样子. 但实际上还是需要先考虑贪心. 当k==1的时候 只有一次操作机会.显然可以把那些比第一个位置小的都给扔掉. 然后可以得知剩下序列中的最大值一定会被选择. ...
- [Noi2016]国王饮水记
来自FallDream的博客,未经允许,请勿转载,谢谢. 跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1 号城市中.跳蚤国最大的问题就是饮水问题,由于首都中居住的跳蚤实在太多,跳蚤国王 ...
- BZOJ4654/UOJ223 [Noi2016]国王饮水记
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- uoj233/BZOJ4654/洛谷P1721 [Noi2016]国王饮水记 【dp + 斜率优化】
题目链接 uoj233 题解 下面不加证明地给出几个性质: 小于\(h[1]\)的城市一定是没用的 任何城市联通包含\(1\)且只和\(1\)联通一次 联通顺序从小到大最优 单个联通比多个一起联通要优 ...
- [NOI 2016]国王饮水记
Description 题库链接 给出 \(n\) 个水杯,每个水杯装有不同高度的水 \(h_i\) ,每次可以指定任意多水杯用连通器连通后断开,问不超过 \(k\) 次操作之后 \(1\) 号水杯的 ...
- *UOJ#223. 【NOI2016】国王饮水记
$n \leq 8000$的数列,问不超过$m \leq 1e9$次操作后第一个数字最大是多少.操作:选一些数,把他们变成他们的平均值.需要保留$p \leq 3000$位小数,提供了一个小数高精度库 ...
- BZOJ4654 NOI2016国王饮水记(动态规划+三分)
有很多比较显然的性质.首先每个城市(除1外)至多被连通一次,否则没有意义.其次将城市按水位从大到小排序后,用以连通的城市集合是一段前缀,并且不应存在比1城市还小的.然后如果确定了选取的城市集合,每次选 ...
随机推荐
- 2019/1.7 js面向对象笔记
面向对象 1.构造函数里的属性怎么看?看this,谁前面有this谁就是属性. num不是属性,是私有作用域下的私有变量. 2.如何查找面向对象中的this 1.构造函数的this指向实例对象 2.如 ...
- 我的Spring Boot学习记录(一):自动配置的大致调用过程
1. 背景 Spring Boot通过包管理工具引入starter包就可以轻松使用,省去了配置的繁琐工作,这里简要的通过个人的理解说下Spring Boot启动过程中如何去自动加载配置. 本文中使用的 ...
- Java工具类——通过配置XML验证Map
Java工具类--通过配置XML验证Map 背景 在JavaWeb项目中,接收前端过来的参数时通常是使用我们的实体类进行接收的.但是呢,我们不能去决定已经搭建好的框架是怎么样的,在我接触的框架中有一种 ...
- 正确启动从GitHub上下载的vue项目:vueAdmin-template
先讲重点,后上相关资料: 遇到的问题:在启动从GitHub上下载的vue项目:vueAdmin-template 时报错:'webpack-dev-server' 不是内部或外部命令,也不是可运行的程 ...
- Nano Server速记
入门参考https://docs.microsoft.com/zh-cn/windows-server/get-started/nano-server-quick-start 1.创建VHD Impo ...
- arcgis api 4.x for js之基础地图篇
arcgis api3.x for js转向arcgis api4.x,我也是最近的3-4个月时间的事情,刚好公司有个webgis项目需要展示三维场景,项目选择arcgis api4.x.我纯碎记录一 ...
- Webpack4教程 - 第二部分,使用loader处理scss,图片以及转换JS
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://wanago.io/2018/07/16/webpack-4-course-par ...
- 【原】Java学习笔记033 - IO
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 需求:继承关系中爷 ...
- js坚持不懈之12:var b = {a:1};
今天看到一篇博客,在声明一个变量的时候用了如下格式的语法: var b = {a:1}; 不明白,百度一下.作如下解释: var: 声明一个变量 b: 表示变量的名称 =: 赋值符号 {}: 表示一个 ...
- 微信、qq可以上网,但是浏览器却不能上网怎么办
问题描述:微信.qq可以上网,但是浏览器却不能上网怎么办? 解决办法(步骤如下):(1)打开360安全卫士,点击更多 (2)进入到更多中,点击断网急救箱 (3)进入到断网急救箱,点击全面诊断 (4)一 ...