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

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. centos报错:Could not retrieve mirrorlist http://mirrorlist.centos.org/

    检查是否可以上网. ping 114.114.114.114 如果不可以,调试通.通了之后下一步: 然后检查DNS设置是否正常. ping www.baidu.com 不正常的话,设置DNS,如下: ...

  2. .NET程序设计实验一

    实验一  语言基础 一.实验目的 1. 熟悉Visual Stido.NET 实验环境: 2. 掌握控制台程序的编写方法: 3. 掌握C#程序设计语言的语法基础: 4. 掌握控制语句和数组的使用. 二 ...

  3. 给大家补充一个结构体的例子:下面TwoNumber就是一个形式上的结构体

    给大家补充一个结构体的例子:下面TwoNumber就是一个形式上的结构体: class TwoNumber {     int num1;     int num2; } public class T ...

  4. MySQL数据库设置编码格式和时区

    MySQL数据库设置编码格式和时区 MySQL5版本: url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8 MySQL6版本及以上 ...

  5. Android实现秒开效果

    0x01 创建SplashActivity 新建一个Activity,取名为SplashActivity 0x02 新建资源 在res/drawable下新建一个splash.xml文件和名为ig_s ...

  6. python数据类型内置的方法

    数据类型的内置方法 在日常生活中不同类型的数据具有不同的功能 eg:表格数据文件具有处理表格的各项功能(透视表 图形化 公式计算) 视频数据文件具有快进 加速等各项功能 ... 1.整型int # 方 ...

  7. swagger不再是第一选择了

    ​ 一.前言 工欲善其事,必先利其器 最近对 API 接口协作的软件研究了好久,市面上的软件都下载用了一轮,下面给大家介绍其中的最强「神器」 Apifox. Apifox 官网:apifox.cn 在 ...

  8. QT的MYSQL驱动库编译

    QT的MYSQL驱动库编译 需要准备QT的源码Src,此次编译64位 在QTCreator中打开mysql.pro 修改两个pro 文件,下图为改好 1.mysql.pro TARGET = qsql ...

  9. 基于easyx的小时钟

    #include <graphics.h> #include <math.h> #include <conio.h> #define PI 3.141592654 ...

  10. 三、DOS命令

    常用的DOS命令 #盘符切换 D: #查看当前目录下的所有文件 dir #切换目录 cd+空格+/d+空格+路径 #返回上一级 cd+空格+.. #清理屏幕 cls #退出终端 exit #查看电脑 ...