CF335E Counting Skyscrapers 题解
提供一种最劣解第一且巨大难写的做法(
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 题解的更多相关文章
- 【SP26073】DIVCNT1 - Counting Divisors 题解
题目描述 定义 \(d(n)\) 为 \(n\) 的正因数的个数,比如 \(d(2) = 2, d(6) = 4\). 令 $ S_1(n) = \sum_{i=1}^n d(i) $ 给定 \(n\ ...
- 【codeforces 335E】 Counting Skyscrapers
http://codeforces.com/problemset/problem/335/E (题目链接) 题意 懒得写了= = Solution 这题咋不上天= =. 参考题解:http://blo ...
- 【CF335 E】Counting Skyscrapers
题意 有一排高楼,每一栋高楼有一个正整数高度,高度为 \(i\) 的概率为 \(2^{-i}\).一栋楼的每层从下往上依次编号为 \(0,1,2,\cdots,i-1\). 为了出题,大楼之间安装了溜 ...
- P4778 Counting Swaps 题解
第一道 A 掉的严格意义上的组合计数题,特来纪念一发. 第一次真正接触到这种类型的题,给人感觉好像思维得很发散才行-- 对于一个排列 \(p_1,p_2,\dots,p_n\),对于每个 \(i\) ...
- POJ 2386 Lake Counting 搜索题解
简单的深度搜索就能够了,看见有人说什么使用并查集,那简直是大算法小用了. 由于能够深搜而不用回溯.故此效率就是O(N*M)了. 技巧就是添加一个标志P,每次搜索到池塘,即有W字母,那么就觉得搜索到一个 ...
- CF908A New Year and Counting Cards 题解
Content 有 \(n\) 张卡牌,每张卡牌上只会有大小写字母和 \(0\sim 9\) 的阿拉伯数字.有这样一个描述:"如果卡牌正面写有元音字母(\(\texttt{A,E,I,O,U ...
- The 2013 South America/Brazil Regional Contest 题解
A: UVALive 6525 cid=61196#problem/A" style="color:blue; text-decoration:none">Atta ...
- Codeforces 1138 - A/B/C/D/E - (Undone)
链接:https://codeforces.com/contest/1137 A - Skyscrapers 题解:对于每一段 $1$ 和每一段 $2$,统计他们的长度.因此对于相邻的两段长度求较小值 ...
- 【题解】Counting D-sets(容斥+欧拉定理)
[题解]Counting D-sets(容斥+欧拉定理) 没时间写先咕咕咕. vjCodeChef - CNTDSETS 就是容斥,只是难了一二三四五\(\dots \inf\)点 题目大意: 给定你 ...
随机推荐
- 活字格发布新版本,插件公开,引领Web开发新潮流
日前,活字格Web 应用生成平台发布V4.0版本,首次公开插件机制,强大的扩展性和系统集成能力,引起业内瞩目. 活字格是由西安葡萄城自主研发的 Web 应用生成平台,提供易用的类Excel可视化设计器 ...
- APK安装流程概述
pre { background: none left top repeat scroll rgba(0, 0, 0, 0); border: 1px solid rgba(0, 0, 0, 1); ...
- C++五子棋(六&七)——游戏结束
规则原理 如图 判断游戏结束 chessData.h //row,col 表示当前落子 bool checkWin(ChessData* game, int row, int col); 横.竖.斜( ...
- Redis HyperLogLog 是什么?这些场景使用它,让我枪出如龙,一笑破苍穹
在移动互联网的业务场景中,数据量很大,我们需要保存这样的信息:一个 key 关联了一个数据集合,同时对这个数据集合做统计. 比如: 统计一个 APP 的日活.月活数: 统计一个页面的每天被多少个不同账 ...
- 『现学现忘』Git基础 — 6、Git的操作流程
目录 1.Git的基本操作流程 2.工作区.暂存区.版本库的区别 (1)工作区 (2)版本库 (3)暂存区 (4)通过新增文件理解三个区的关系 (5)说明 1.Git的基本操作流程 初始化一个本地版本 ...
- R语言_格兰因果检验
#当前文件路径 getwd() #设置当前路径,注意转译 setwd("C://Users//Administrator//Desktop//R_test") #导入数据 data ...
- Percona停服俄罗斯
2022年3月9日,MySQL重要分支Percona宣布,他们将停止与俄罗斯和白俄罗斯的组织开展新业务,直至另行通知. Percona为支持员工而采取的一些行动如下: 已经在乌克兰目前安全的部分获得了 ...
- LCA的离线快速求法
最常见的LCA(树上公共祖先)都是在线算法,往往带了一个log.有一种办法是转化为"+-1最值问题"得到O(n)+O(1)的复杂度,但是原理复杂,常数大.今天介绍一种允许离线时接近 ...
- Day 005:PAT练习--1047. 编程团体赛(20)
编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜.现给定所有队员的比赛成绩,请你编写程序找出冠军队. 输入格式: 输入第一行给出一个正整 ...
- 基于语义感知SBST的API场景测试智能生成
摘要:面对庞大服务接口群,完备的接口测试覆盖和业务上下文场景测试看护才有可能保障产品服务的质量和可信.如果你想低成本实现产品和服务的测试高覆盖和高质量看护,这篇文章将为你提供你想要的. 本文分享自华为 ...