提供一种最劣解第一且巨大难写的做法(

Bob

显然真正的楼量可以达到 \(314!\),是没办法直接做的,再加上唯一方案的样例,可以猜测有简单的结论。

考虑当楼高度为 \(k(k<h)\) 时,每种高度对答案的贡献为 \(2^{k-1}\times 2^{-k}\),即 \(\frac{1}{2}\),当楼高度为 \(k(k \ge h)\) 时,每种高度对答案的贡献和为 \(2^k\times 2^{-k}\),即 \(1\)。显然贡献都与 \(h\) 无关,也就是结论只和 \(n\) 有关,随便推几组数据再加上样例,容易猜出答案即为 \(n\)。

Code:

void Sub2(){
scanf("%d%d",&n,&h);
printf("%d\n",n);
}

Alice

观察到高度 \(\ge h\) 的楼本质上是一致的,可以钦定楼的高度区间为 \([1,h]\)(高度为 \(h\) 的概率变为 \(2^{1-h}\))。

设 \(k\) 号楼的高度最高,则 Bob 一定会经过 \(k\) 号楼。容易发现,在 \(k\) 号楼前,Bob经过的楼的高度单调不降,\(k\) 号楼后单调不升

注意,为了防止重复计算,若高度相同,钦定靠前的最高。

然后就可以转移了。

设 \(f_{i,j,k,0/1}\) 表示转移完第 \(i\) 栋楼,最后一个经过的 \(x\) 号楼的高度为 \(j\),\([x+1,i]\) 中最大高度为 \(k\),是/否 经过最高的楼的期望

设 \(g_{i,j,k,0/1}\) 表示转移完第 \(i\) 栋楼,最后一个经过的 \(x\) 号楼的高度为 \(j\),\([x+1,i]\) 中最大高度为 \(k\),是/否 经过最高的楼的概率

DP的时候用刷表法,枚举第 \(i\) 栋楼的高度转移即可。时间复杂度 \(O(nh^3)\) 要卡亿点常并滚动数组。

Code:

const double eps=1e-15;
const int maxn=30010;
const int maxh=35;
int n,h;
double g[2][maxh][maxh][2];
double f[2][maxh][maxh][2];
double V[maxh],S[maxh];
void Sub1(){
scanf("%d%d",&n,&h);
for(int i=0;i<h;i++){
V[i]=1.0/(1<<i+1),S[i]=(1-1.0/(1<<i));
f[1][i][0][0]=V[i]+0.5,g[1][i][0][0]=V[i];
}
if(h) V[h]=V[h-1],S[h]=(1-1.0/(1<<h));
else V[h]=1;
for(int i=0;i<=h;i++) f[1][i][0][1]=V[i],g[1][i][0][1]=V[i];
//以上是初始化
double tmp1,tmp2,tmp;
for(int i=1,ii=1,iii=0;i<n;i++,ii^=1,iii^=1){
memset(f[iii],0,sizeof(f[iii]));
memset(g[iii],0,sizeof(g[iii]));
//注意,为了处理当j=i时(Bob经过当前楼)k也为0的情况
//这里枚举的k,u都加了1(j=0时k才为0) //为了卡常,转移的式子很丑,但本质是一样的
for(int j=0;j<=h;j++)
for(int k=0;k<=j;k++){
tmp1=f[ii][j][k][0],tmp2=g[ii][j][k][0],tmp=tmp2/2;
if(tmp1>eps){
//u<=k
f[iii][j][k][0]+=tmp1*S[k];
g[iii][j][k][0]+=tmp2*S[k];
tmp1*=V[k],tmp2*=V[k];
//--------
for(int u=k+1;u<=h+1;u++){
if(u-1>=j) f[iii][u-1][0][0]+=tmp1+tmp,g[iii][u-1][0][0]+=tmp2;
else f[iii][j][u][0]+=tmp1,g[iii][j][u][0]+=tmp2;
if(u-1>j) f[iii][u-1][0][1]+=tmp1,g[iii][u-1][0][1]+=tmp2;
if(u<h) tmp1/=2,tmp2/=2;
}
f[iii][h][0][0]+=tmp;
}
tmp1=f[ii][j][k][1],tmp2=g[ii][j][k][1],tmp=tmp2/2;
if(tmp1>eps){
//u<=k
f[iii][j][k][1]+=tmp1*S[k];
g[iii][j][k][1]+=tmp2*S[k];
tmp1*=V[k],tmp2*=V[k];
//--------
for(int u=k+1;u<=j+1;u++){
f[iii][u-1][0][1]+=tmp1+tmp,g[iii][u-1][0][1]+=tmp2;
if(u-1<j) f[iii][j][u][1]+=tmp1,g[iii][j][u][1]+=tmp2;
if(u<h) tmp1/=2,tmp2/=2;
}
if(j==h) f[iii][h][0][1]+=tmp;
}
}
}
double ans=0;
for(int i=0;i<=h;i++)
ans+=f[n&1][i][0][1];
printf("%.9lf",ans);
}

能不能更快?

上述期望DP本质上是分了 \([1,k],[k+1,j][j+1,h]\) 三个区间分别转移行和列,考虑将决策点放到线段树上,则问题转换为了线段树的区间修改/单点查询,时间复杂度 \(O(nh^2\log h)\)。

但由于要对 \(f,g\)、是否经过最高楼、行或列分类讨论,所以要开 \(8nh\) 棵线段树,本地极限数据要跑 \(10s+\),没有实质效果。

能不能更快?

观察到转移方程与 \(n\) 无关,考虑构造 \(h\times h\) 的矩阵,跑矩阵快速幂即可,时间复杂度 \(O(h^3logn)\),可以通过本题,时间与空间上都更优。

CF335E Counting Skyscrapers 题解的更多相关文章

  1. 【SP26073】DIVCNT1 - Counting Divisors 题解

    题目描述 定义 \(d(n)\) 为 \(n\) 的正因数的个数,比如 \(d(2) = 2, d(6) = 4\). 令 $ S_1(n) = \sum_{i=1}^n d(i) $ 给定 \(n\ ...

  2. 【codeforces 335E】 Counting Skyscrapers

    http://codeforces.com/problemset/problem/335/E (题目链接) 题意 懒得写了= = Solution 这题咋不上天= =. 参考题解:http://blo ...

  3. 【CF335 E】Counting Skyscrapers

    题意 有一排高楼,每一栋高楼有一个正整数高度,高度为 \(i\) 的概率为 \(2^{-i}\).一栋楼的每层从下往上依次编号为 \(0,1,2,\cdots,i-1\). 为了出题,大楼之间安装了溜 ...

  4. P4778 Counting Swaps 题解

    第一道 A 掉的严格意义上的组合计数题,特来纪念一发. 第一次真正接触到这种类型的题,给人感觉好像思维得很发散才行-- 对于一个排列 \(p_1,p_2,\dots,p_n\),对于每个 \(i\) ...

  5. POJ 2386 Lake Counting 搜索题解

    简单的深度搜索就能够了,看见有人说什么使用并查集,那简直是大算法小用了. 由于能够深搜而不用回溯.故此效率就是O(N*M)了. 技巧就是添加一个标志P,每次搜索到池塘,即有W字母,那么就觉得搜索到一个 ...

  6. CF908A New Year and Counting Cards 题解

    Content 有 \(n\) 张卡牌,每张卡牌上只会有大小写字母和 \(0\sim 9\) 的阿拉伯数字.有这样一个描述:"如果卡牌正面写有元音字母(\(\texttt{A,E,I,O,U ...

  7. The 2013 South America/Brazil Regional Contest 题解

    A: UVALive 6525 cid=61196#problem/A" style="color:blue; text-decoration:none">Atta ...

  8. Codeforces 1138 - A/B/C/D/E - (Undone)

    链接:https://codeforces.com/contest/1137 A - Skyscrapers 题解:对于每一段 $1$ 和每一段 $2$,统计他们的长度.因此对于相邻的两段长度求较小值 ...

  9. 【题解】Counting D-sets(容斥+欧拉定理)

    [题解]Counting D-sets(容斥+欧拉定理) 没时间写先咕咕咕. vjCodeChef - CNTDSETS 就是容斥,只是难了一二三四五\(\dots \inf\)点 题目大意: 给定你 ...

随机推荐

  1. ES6-11学习笔记--数组遍历

    ES5中数组遍历方式: for循环 forEach():没有返回值,只是针对每个元素调用func map():返回新的Array,每个元素为调用func的结果 filter():返回符合func条件的 ...

  2. IDEA修改代码后不用重新启动项目即可刷新

    1.File--Settings--Build 2.Build,Execution,Deplyment--Compiler 3.选中打勾 "Build project automatical ...

  3. CCF201503-1图像旋转

    问题描述 旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度. 计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可. 输入格式 输入的第一行包含 ...

  4. vue-cli打包后dist文件运行空白和背景图显示问题详解

    1.文件引用路径.我们直接运行打包后的文件夹中的index.html文件,会看到网页一片空白,f12调试,全是css,js路径引用错误的问题. 解决:到config文件夹中打开index.js文件. ...

  5. .NET如何快速比较两个byte数组是否相等

    目录 前言 评测方案 几种不同的方案 For循环 Memcmp 64字长优化 SIMD Sse Avx2 SequenceCompare 总结 参考文献 前言 之前在群里面有群友问过一个这样的问题,在 ...

  6. spring-bean依赖注入-02(通过p命名空间注入)

    上一篇博客讲述了为什么使用spring依赖注入,怎么注入,详见 spring-bean依赖注入-01(等你来点击) 废话不多说,开始使用p命名空间进行set注入 使用另外一种注入方式是这样的(具体实现 ...

  7. 进程的概念及multiprocess模块的使用

    一.进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在 ...

  8. 【面试普通人VS高手系列】Spring Boot的约定优于配置,你的理解是什么?

    对于Spring Boot约定优于配置这个问题,看看普通人和高手是如何回答的? 普通人的回答: 嗯, 在Spring Boot里面,通过约定优于配置这个思想,可以让我们少写很多的配置, 然后就只需要关 ...

  9. Hystrix熔断初体验

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring ...

  10. SpringMVC初学习

    # SpringMVC快速入门 @[TOC](文章目录) --- # 前言 `提示:这里可以添加本文要记录的大概内容:` 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习 ...