【agc012E】Camel and Oases
Description
有一排点,两点间有一定距离,初始的时候有一个行走值\(v\),如果说两点间距离不超过\(v\),那么可以在这两点间自由行走,如果当前\(v>0\)那么可以选择突然出现在任意一点,但是这样做之后\(v\)会减半(下取整),问每个位置出发能否到达所有的位置至少一次
Solution
额其实感觉关键还是模型的转化
其实我们可以比较形象地将每个\(v\)(就是不停除以\(2\)直到\(0\),中途得到的那堆\(v\)),看成“一层”,具体举个例子的话就是:当\(v=4\)的时候,第一层为\(v=4\),第二层为\(v=2\),第三层为\(v=1\),第四层为\(v=0\),这样
然后每次突然出现其实就相当于往上走了一层,而每层中,有一些区间是可以在区间内随便走的,我们将这些区间看成若干条线段,那么现在的问题就变成了,每层选一条线段,问是否能够覆盖整个区间
想不到吧然后因为层数上限是\(19\)所以。。这是一道状压dp的题目==
所以首先,我们先将每一层中的线段处理出来,将第\(i\)层的线段存在\(seg[i]\)数组里面,只用存右端点即可,左端点可以由前一条线段的右端点\(+1\)得到
考虑一下大概要用什么样的方式统计答案,我们可以考虑枚举第一层的每条线段\((l_i,r_i)\),如果说存在一种方案使得从\(1\)开始覆盖到一个\(>=l_i-1\)的位置,从\(n\)开始覆盖到一个\(<=r_i+1\)的位置,那么这段线段中的每一个点都是\(Possible\)的,否则就是\(Impossible\)
那么所以,我们考虑维护两个数组\(tol\)和\(tor\),其中\(tor[i]\)表示线段选择状态(如果这层选了线段那么对应的二进制位为\(1\)否则为\(0\))为\(i\)的情况下,从\(1\)开始往右最远能覆盖到的位置,\(tol[i]\)表示从\(n\)开始往左最远能覆盖到的位置,注意,因为最后统计答案的时候,第一层的线段是要枚举的,所以我们在计算\(tor\)和\(tol\)的枚举状态的时候,不能包含第一层
接下来定义两个过程:\(expandReft(which,x)\)表示在第\(which\)层的线段中,严格大于\(x\)的第一个右端点,\(expandLight(which,x)\)表示在第\(which\)层的线段中,严格小于\(x\)的最靠近\(n\)的右端点
那么我们可以得到转移式子:
tor[st|St(i)]&=max(tor[st|St(i)],expandRight(i,tor[st]))\\
tol[st|St(i)]&=min(tol[st|St(i)],expandLeft(i,tol[st]-1))\\
\end{aligned}
\]
至于为什么要用\(tol[st]-1\)的话。。是因为如果直接找\(tol[st]\)的话,我们可能找到\(tol[st]\),这就说明有一段以\(tol[st]-1\)为右端点的区间以及一段以\(tol[st]\)为左端点的区间,然而这个时候我们应该找前者而不是后者会出些小问题==(不过也可能只是实现方式的问题。。具体都是看二分查找要怎么写吧都是一些实现上的细节问题qwq)
那么最后一个小问题就是,如果说第一层有很多条线段的话那就很凉凉,然而实际上,我们发现如果说第一层的线段条数\(>logv+1\)的话。。就根本不可能覆盖完了(层数不够),所以我们可以在计算之前先判一下这种全部都是\(Impossible\)的情况
那所以我们的总复杂度就是\(O(nlogv+vlognlogv)\)了
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=2*(1e5)+10,ST=1<<20,TOP=20,inf=2e9;
int seg[TOP+1][N],d[N],tor[ST],tol[ST],a[N];
int n,m,v,lg,all;
bool in(int st,int x){return st>>x-1&1;}
int St(int x){return 1<<x-1;}
void get_seg(){
for (int i=1;i<=lg;++i){
seg[i][0]=0;
for (int j=1;j<=n;++j){
if (j==1||d[j-1]>v>>i-1) ++seg[i][0];
seg[i][seg[i][0]]=j;
}
}
}
bool firstcheck(){
if (seg[1][0]<=lg) return true;
for (int i=1;i<=n;++i) printf("Impossible\n");
return false;
}
int expand_right(int which,int x){
int l=1,r=seg[which][0],mid,ret=r;
while (l<=r){
mid=l+r>>1;
if (seg[which][mid]>x) ret=mid,r=mid-1;
else l=mid+1;
}
return seg[which][ret];
}
int expand_left(int which,int x){
int l=1,r=seg[which][0],mid,ret=l;
while (l<=r){
mid=l+r>>1;
if (seg[which][mid]<x) ret=mid,l=mid+1;
else r=mid-1;
}
return seg[which][ret]+1;
}
void dp(){
all=1<<lg;
for (int st=0;st<all;++st) tor[st]=0,tol[st]=n+1;
for (int st=0;st<all;st+=2){
for (int i=2;i<=lg;++i){
if (in(st,i)) continue;
tor[st|St(i)]=max(tor[st|St(i)],expand_right(i,tor[st]));
tol[st|St(i)]=min(tol[st|St(i)],expand_left(i,tol[st]-1));
}
}
}
void get_ans(){
int L,R;
bool ok;
for (int i=1;i<=seg[1][0];++i){
L=i==1?1:seg[1][i-1]+1; R=seg[1][i];
ok=false;
for (int st=0;st<all&&!ok;st+=2)
if (L-1<=tor[st]&&tol[(all-1)-st-1]<=R+1) ok=true;
for (int j=L;j<=R;++j) printf(ok?"Possible\n":"Impossible\n");
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d%d",&n,&v);
for (int i=1;i<=n;++i) scanf("%d",a+i);
d[n]=inf;
for (int i=1;i<n;++i) d[i]=a[i+1]-a[i];
lg=0;
while ((v>>lg)>0) ++lg;
++lg;
get_seg();
if (!firstcheck()) return 0;
dp();
get_ans();
}
【agc012E】Camel and Oases的更多相关文章
- 【AGC012E】 Camel and Oases ST表+状压dp
题目大意:一排点,两点间有距离. 初始你有一个行走值$v$,如果相邻两点距离不超过$v$你可以自由在这两点行走. 当$v$大于$0$时,你可以选择某一时刻突然飞到任意点,这样做后$v$会减半(下取整) ...
- 【AtCoder】【模拟】【模型转化】Camel and Oases(AGC012)
题意: 有一个骆驼,n个绿洲遍布在数轴上,第i个绿洲的坐标为x[i],保证x[i]单增.骆驼的驼峰有体积初始值V.当驼峰的体积变为v的时候,驼峰中至多只能够存储v L的水.骆驼希望走完所有的绿洲,并且 ...
- 【Mybatis】MyBatis配置文件的使用(二)
本例在[Mybatis]MyBatis快速入门(一)基础上继续学习XML映射配置文件 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properti ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
随机推荐
- Linux☞权限数字表示法
权限数字表示法: 1.Linux有三种访问权限: a.可读:r(Read) b.可写:w(Write) c.可执行:x(eXcute) 2.简单说说如何去看该文件的访问权限呢?一般我们执行命令,查看目 ...
- SICP读书笔记 1.3
SICP CONCLUSION 让我们举起杯,祝福那些将他们的思想镶嵌在重重括号之间的Lisp程序员 ! 祝我能够突破层层代码,找到住在里计算机的神灵! 目录 1. 构造过程抽象 2. 构造数据抽象 ...
- IO多路复用(二) -- select、poll、epoll实现TCP反射程序
接着上文IO多路复用(一)-- Select.Poll.Epoll,接下来将演示一个TCP回射程序,源代码来自于该博文https://www.cnblogs.com/Anker/p/3258674.h ...
- Visionpro学习网
重码网是一个在线机器视觉学习网站,推出了Halcon,Visionpro机器视觉学习视频教程,视频内容通俗易懂,没有编程基础的同学,照着视频练习,也同样可以学会. 学机器视觉,拿高薪,成就技术大拿.重 ...
- 初试Gevent – 高性能的Python并发框架
Gevent是一个基于greenlet的Python的并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效. 于greenlet.eventlet相比,性能 ...
- 20181120-10 Beta阶段第2周/共2周 Scrum立会报告+燃尽图 7
此作业要求参见:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2415] 版本控制地址 [https://git.coding.n ...
- QTcpServer实现多客户端连接
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QTcpServer实现多客户端连接 本文地址:https://www.techiel ...
- 【final】评价①
飞天小女警添加猜你喜欢功能,个人很喜欢.当推荐产品不喜欢的时候还有其他的选择,很人性化. 金州勇士将管理人员的角色分开,使整个系统的分工更明确,也更清晰. 新蜂的俄罗斯方块随着等级的提升有直观的颜色变 ...
- 【php】header下载文件后,文件变大的问题;(ob_clean()清空缓存)
事由: 按照常理,为了下载一个生产的文件,都是使用header函数,指定下文件信息,然后开始下载,但是下载后发现,文件体积总是比源文件要大2个字节,源文件是24字节,下载后是26字节,查看服务器返回的 ...
- java 数据结构与算法 之查找法
一.二分查找法 二分查找就是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找:如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素. @Test public ...