题意:

有一个骆驼,n个绿洲遍布在数轴上,第i个绿洲的坐标为x[i],保证x[i]单增。骆驼的驼峰有体积初始值V。当驼峰的体积变为v的时候,驼峰中至多只能够存储v L的水。骆驼希望走完所有的绿洲,并且可以向下面这样来走:

1.走距离d,消耗驼峰中d L的水,但是驼峰的体积不会减少。任意时候驼峰中的水的体积均不能够为负数;

2.跳跃到任意一个位置,消耗完所有的水,并且让驼峰的体积变为v/2。该操作在v=0的时候是不能够进行的。

骆驼能够在绿洲将水补满至v。且一个绿洲可以多次访问并进行补给。最后要求你输出从每个位置出发,能否走完所有的绿洲。

数据范围:

N,V<=2*1e5 ,-1e9<=x[i]<=1e9 ,且x是单增的。

思路:

首先看完题目,我们可以发现v/2这个操作是十分玄学的。这意味着只会减少log(V)+1次,就不能够再进行任何的移动了。也说明了v的取值只会有log(V)+2种,这个数量级是很小的。

那么对于某一个v而言,骆驼能够在一些连续的绿洲之间任意的穿梭,也就形成了一些线段。具体而言就是假如说x[i+1]-x[i]<=v,那么这两个绿洲就是联通的,就可以让i和i+1处于一条线段中。我们可以发现,当v从V变换到0的时候,每一条线段的长度是在逐渐变短的,而线段的数量在逐渐增多。也就是说,v越小,骆驼的移动能力越差。现在这个问题就变成了强迫你选择了第一层(也就是v=V的那一层)中的某一条线段,在剩下的每一层当中,选出至多一条线段,能否存在一种方式使得最后选出来的所有的线段能够覆盖完所有的绿洲。

对于这个问题而言,瞬间就简化了不少。可以定义f1[state],表示在选择state(第i位为0表示第i层没有选择线段,第i位为1表示第i层选择了一条线段)的时候,(线段从最左边开始选)能够覆盖完全的最靠右的位置;定义f2[state],表示在选择state的时候,(线段从最右边开始选)能够覆盖完全的最靠左的位置。最后再扫一遍第一层中的所有的线段,表示强行选择其中的某一条线段,然后找是否有一个state,满足第0位不为1(第一层已经被确定了),且f1[state],f2[全集-state-1],加上这条线段,使得能够覆盖完所有的绿洲。

这样子看上去似乎问题已经解决了,但是当V奇小的时候,第一层最坏可能有n条线段(一个点一条),然后就变成了\(O(n2^{log_n})=O(n^2)\)的状态。仔细分析之后,我们可以发现,假如第一层的线段数量大于了logV+2,那么由于接下来的线段只会越来越短并且越来越多,就算是选择第一层的所有线段也需要>logV+2条线段,而一共才能够选择log(V)+2条线段线段,那就显然不可能有解了。全部输出Impossible即可。

这样子就变为了O(logV * n)的时间复杂度了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000000
#define INF 2000000000
using namespace std;
int n,V,x[MAXN+5];
int cnt[25];//cnt用于计算每一层所有的线段数
int l[25][MAXN+5],r[25][MAXN+5];//l表示线段的左端点,r表示的则是右端点
int f1[MAXN*5+5],f2[MAXN*5+5];//如思路中的定义
bool ans[MAXN+5];//ans记录的是对于某一条线段的答案,不是某个绿洲的答案
void Init()
{
for(int i=0;i<=MAXN*5+3;i++)
f1[i]=0,f2[i]=INF;
}
int UpFind(int id,int pos)//找l在pos+1的左边的线段,也就是能够向右扩展的最靠右的线段
{
pos++;
int p=upper_bound(l[id]+1,l[id]+cnt[id]+1,pos)-l[id];
p--;
if(p<=0)
return pos;
return max(r[id][p],pos-1);
}
int LowFind(int id,int pos)//找r在pos-1的右边的线段,也就是能够向左扩展的最靠左的线段
{
pos--;
int p=lower_bound(r[id]+1,r[id]+cnt[id]+1,pos)-r[id];
if(p>=cnt[id]+1)
return pos;
return min(l[id][p],pos+1);
}
int main()
{
Init();
scanf("%d %d",&n,&V);
int logV=0;
for(logV=0;(1<<logV)<=V;logV++);//求出来的实际上是logV+1
for(int i=1;i<=n;i++)
scanf("%d",&x[i]);
x[n+1]=INF;
x[0]=-INF;//便于操作
for(int LG=0;LG<=logV;LG++)
{
int d=V/(1<<LG);
cnt[LG]=1;
l[LG][1]=1;
//求线段
for(int i=1;i<=n;i++)
{
r[LG][cnt[LG]]=i;
if(x[i+1]-x[i]>d)
{
cnt[LG]++;
l[LG][cnt[LG]]=i+1;
}
}
cnt[LG]--;
}
if(cnt[0]>logV+1)//特判
{
for(int i=1;i<=n;i++)
printf("Impossible\n");
return 0;
}
int all=(1<<(logV+1));
f1[0]=0,f2[0]=n+1;//预处理两个f数组
for(int s=0;s<all;s+=2)
for(int i=0;i<=logV;i++)
{
if(!(s&(1<<i)))
continue;
f1[s]=max(f1[s],UpFind(i,f1[s-(1<<i)]));
f2[s]=min(f2[s],LowFind(i,f2[s-(1<<i)]));
}
for(int i=1;i<=cnt[0];i++)//枚举第一层的每一条线段
{
int ln=l[0][i],rn=r[0][i];
for(int s1=0;s1<all;s1+=2)
{
int s2=all-1-s1-1;
int lpos=f1[s1];
int rpos=f2[s2];
if(lpos>=ln-1&&rpos<=rn+1)//看能否覆盖所有的绿洲
{
ans[i]=true;//存的是线段的答案
break;
}
}
}
int pos=1;
for(int i=1;i<=n;i++)
{
if(ans[pos]==true)
printf("Possible\n");
else
printf("Impossible\n");
if(x[i+1]-x[i]>V)
pos++;
}
return 0;
}

【AtCoder】【模拟】【模型转化】Camel and Oases(AGC012)的更多相关文章

  1. AGC012 - E: Camel and Oases

    原题链接 题意简述 沙漠中有个排成一条直线的绿洲,一头储水量为的骆驼. 骆驼有两个操作: 走到距离在V以内的一个绿洲. 飞到任意一个绿洲,但V减少一半.V=0时不能飞. 问骆驼依次从每个绿洲出发,能否 ...

  2. 【AtCoder】【模型转化】【二分答案】Median Pyramid Hard(AGC006)

    题意: 给你一个排列,有2*n-1个元素,现在进行以下的操作: 每一次将a[i]替换成为a[i-1],a[i],a[i+1]三个数的中位数,并且所有的操作是同时进行的,也就是说这一次用于计算的a[], ...

  3. 【agc012E】Camel and Oases

    Portal --> agc012 Description 有一排点,两点间有一定距离,初始的时候有一个行走值\(v\),如果说两点间距离不超过\(v\),那么可以在这两点间自由行走,如果当前\ ...

  4. python构建模拟模型——网站独立访问用户数量

    背景:发现一个有趣的现象,即一些用户在每一月都仅仅访问网站一次,我们想要了解这些人数量的变化趋势. 建立数学模型:简化问题,根据瓮模型推导出公式(具体推导见<数据之魅>,有时间再补充... ...

  5. tyvj P1209 - 拦截导弹 平面图最小割&&模型转化

    P1209 - 拦截导弹 From admin    Normal (OI)总时限:6s    内存限制:128MB    代码长度限制:64KB 背景 Background 实中编程者联盟为了培养技 ...

  6. 【2019雅礼集训】【可持久化线段树】【模型转化】D1T2Permutation

    目录 题意 输入格式 输出格式 思路 代码 题意 给定一个长度为n的序列A[],你需要确定一个长度为n的排列P[],定义当前排列的值为: \[\sum_{i=1}^{n}{A[i]P[i]}\] 现在 ...

  7. [bzoj4567][Scoi2016]背单词-Trie+贪心+模型转化

    Brief Description 给你N个互不相同的字符串,记\(S_i\)为第i个字符串,现在要求你指定N个串的出现顺序,我们用\(V_i\)表示第i个字符串是第几个出现的,则V为1到N的一个排列 ...

  8. Wannafly挑战赛26-F. msc的棋盘(模型转化+dp)及一类特殊的网络流问题

    题目链接 https://www.nowcoder.com/acm/contest/212/F 题解 我们先考虑如果已知了数组 \(\{a_i\}\) 和 \(\{b_i\}\),如何判断其是否合法. ...

  9. AGC013 E Placing Squares——模型转化+矩阵乘法

    题目:https://atcoder.jp/contests/agc013/tasks/agc013_e 边长的平方,可以看做是在该范围内放两个不同的球的方案数.两个球可以重合. 题意变成:给长为 n ...

随机推荐

  1. Window下Eclipse+Tomcat远程调试

    需求:       项目在开发环境跑得好好的,但是当发布到服务器上时,却出现了一些意外的问题.服务器上不可能给你装IDE调试工具啊,又没有很好的日志帮助下,这时候就用到了JVM的Java Platfo ...

  2. Mock5 moco框架中post请求如何加入cookies

    接着Mock4中的json文件,再往里面添加一个post 请求. 前面写法不变,后面的请求数据用的是json关键字,返回的response也是json的格式 [ { "description ...

  3. Gym - 101350F Monkeying Around(线段树+树状数组)

    When the monkey professor leaves his class for a short time, all the monkeys go bananas. N monkeys a ...

  4. MTD下的Nand驱动

    目录 MTD下的Nand驱动 引入 平台设备资源文件 关键数据结构 平台框架 s3c24xx_nand_probe nand_scan s3c2410_nand_add_partition add_m ...

  5. Numpy 系列(七)- 常用函数

    在了解了 Numpy 的基本运算操作,下面来看下 Numpy常用的函数.     数学运算函数 add(x1,x2 [,out]) 按元素添加参数,等效于 x1 + x2 subtract(x1,x2 ...

  6. mongodb3.6集群搭建:分片+副本集

    mongodb是最常用的noSql数据库,在数据库排名中已经上升到了前五.这篇文章介绍如何搭建高可用的mongodb(分片+副本)集群. 在搭建集群之前,需要首先了解几个概念:路由,分片.副本集.配置 ...

  7. 在 Visual Studio 中使用 IntelliTrace 快照功能

    今天发现vs2017 IntelliTrace有了一个快照功能,测试一下它的用法 1.选项->IntelliTrace->选择第三项 2.建一个控制台应用程序 3.在main中写一个简单的 ...

  8. [物理学与PDEs]第2章第1节 理想流体力学方程组 1.2 理想流体力学方程组

    1.  质量守恒定律: 连续性方程 $$\bee\label{2_1_2_zl} \cfrac{\p\rho}{\p t}+\Div(\rho{\bf u})=0.  \eee$$ 2.  动量守恒定 ...

  9. 同步Name到Comment 及 同步 Comment 到Name

    在 PowerDesigner执行命令  Tools->Execute Commands->Edit/Run Scripts 代码一:将Name中的字符COPY至Comment中 Opti ...

  10. 两个Html页面之间值得传递

    传值的页面:<a href='stockProductInfo.html?prdId="+v.prdID+"' target='_blank'></html> ...