【AtCoder】【模拟】【模型转化】Camel and Oases(AGC012)
题意:
有一个骆驼,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)的更多相关文章
- AGC012 - E: Camel and Oases
原题链接 题意简述 沙漠中有个排成一条直线的绿洲,一头储水量为的骆驼. 骆驼有两个操作: 走到距离在V以内的一个绿洲. 飞到任意一个绿洲,但V减少一半.V=0时不能飞. 问骆驼依次从每个绿洲出发,能否 ...
- 【AtCoder】【模型转化】【二分答案】Median Pyramid Hard(AGC006)
题意: 给你一个排列,有2*n-1个元素,现在进行以下的操作: 每一次将a[i]替换成为a[i-1],a[i],a[i+1]三个数的中位数,并且所有的操作是同时进行的,也就是说这一次用于计算的a[], ...
- 【agc012E】Camel and Oases
Portal --> agc012 Description 有一排点,两点间有一定距离,初始的时候有一个行走值\(v\),如果说两点间距离不超过\(v\),那么可以在这两点间自由行走,如果当前\ ...
- python构建模拟模型——网站独立访问用户数量
背景:发现一个有趣的现象,即一些用户在每一月都仅仅访问网站一次,我们想要了解这些人数量的变化趋势. 建立数学模型:简化问题,根据瓮模型推导出公式(具体推导见<数据之魅>,有时间再补充... ...
- tyvj P1209 - 拦截导弹 平面图最小割&&模型转化
P1209 - 拦截导弹 From admin Normal (OI)总时限:6s 内存限制:128MB 代码长度限制:64KB 背景 Background 实中编程者联盟为了培养技 ...
- 【2019雅礼集训】【可持久化线段树】【模型转化】D1T2Permutation
目录 题意 输入格式 输出格式 思路 代码 题意 给定一个长度为n的序列A[],你需要确定一个长度为n的排列P[],定义当前排列的值为: \[\sum_{i=1}^{n}{A[i]P[i]}\] 现在 ...
- [bzoj4567][Scoi2016]背单词-Trie+贪心+模型转化
Brief Description 给你N个互不相同的字符串,记\(S_i\)为第i个字符串,现在要求你指定N个串的出现顺序,我们用\(V_i\)表示第i个字符串是第几个出现的,则V为1到N的一个排列 ...
- Wannafly挑战赛26-F. msc的棋盘(模型转化+dp)及一类特殊的网络流问题
题目链接 https://www.nowcoder.com/acm/contest/212/F 题解 我们先考虑如果已知了数组 \(\{a_i\}\) 和 \(\{b_i\}\),如何判断其是否合法. ...
- AGC013 E Placing Squares——模型转化+矩阵乘法
题目:https://atcoder.jp/contests/agc013/tasks/agc013_e 边长的平方,可以看做是在该范围内放两个不同的球的方案数.两个球可以重合. 题意变成:给长为 n ...
随机推荐
- Meterpreter提权详解
0x01 Meterpreter自动提权 1.生成后门程序 我们在kali的命令行下直接执行以下命令获得一个针对windows的反弹型木马: msfvenom -p windows/meterpr ...
- ACM-ICPC 2018 徐州赛区网络预赛 J Maze Designer(最大生成树+LCA)
https://nanti.jisuanke.com/t/31462 题意 一个N*M的矩形,每个格点到其邻近点的边有其权值,需要构建出一个迷宫,使得构建迷宫的边权之和最小,之后Q次查询,每次给出两点 ...
- LFYZ-OJ ID: 1026 数的计数(数的计算)NOIP2001
数的计算(数的计数) 题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数n).先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理: 不作任何处理; 在它的左边加上 ...
- [物理学与PDEs]第1章第6节 电磁场的标势与矢势 6.3 例 --- 电偶极辐射
1. 偶极子: 相距为 $l$, 带电量分别为 $\pm q$ 的一对电荷组成的系统. 称 $$\bex {\bf m}=q{\bf l} \eex$$ 为电偶极矩, 其中 ${\bf l}$ 为 $ ...
- Jsp1
jsp代码中包含两类:jsp元素和template data. template模板 data:jsp引擎不处理的部分,就是<%....%>之外的部分,直接给浏览器显示. <%! % ...
- C语言官网蓝桥杯训练1115DNA
这道题是比较简单的输出字符图形的题,但是有几个坑还是要注意下. 1.题中所述的X是大写的,不要看成小写了.(我就错了好几次) 2.每一行输出最后的X后不能在输出空格. 3.输出两个DNA中间有一个空行 ...
- 前端 $.parseJson()
$.parseJSON() 函数用于将符合标准格式的的JSON字符串转为与之对应的JavaScript对象. 例子: 这里首先给出JSON字符串集,字符串集如下: var data=" { ...
- MySQL -- 关闭 binlog
LNMP一键安装包安装的MySQL默认是开启了日志文件的,如果数据操作比较频繁就会产生大量的日志,在/usr/local/mysql /var/下面产生mysql-bin.0000* 类似的文件,而且 ...
- Laravel -- 邮箱功能配置问题
```` 今天碰到了这块的问题,还是记一下 ```` 关于邮箱: 品牌:腾讯qq.网易163 等 种类:个人.企业 邮箱服务器种类 配置教程 https://jingyan.baidu.com/art ...
- java集合(list,set,map)
集合 集合与数组 数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用. 集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用. ...