【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 ...
随机推荐
- 忘掉Ghost!利用Win10自带功能,玩转系统备份&恢复 -- 关于系统恢复的深度思考
上一篇文章讲了,系统可以正常启动,如何从D盘恢复系统到C盘的情况. 如果系统不能启动,要怎么去恢复系统,恢复后会是什么结果? 先说明系统结构: 系统版本:Windows 10 (1709) 硬盘1(5 ...
- 「LibreOJ NOI Round #1」验题
麻烦的动态DP写了2天 简化题意:给树,求比给定独立集字典序大k的独立集是哪一个 主要思路: k排名都是类似二分的按位确定过程. 字典序比较本质是LCP下一位,故枚举LCP,看多出来了多少个独立集,然 ...
- 第四章:条件语句(if)和循环结构(while)
1.流程控制 含义与作用 Python程序执行,一定按照某种规律在执行 a.宏观一定是自上而下(逻辑上方代码一定比逻辑下方代码先执行):顺序结构b.遇到需要条件判断选择不同执行路线的执行方式:分支结构 ...
- /etc/profile文件被改坏导致命令不可用
这几天在装一个软件,设置环境变量的时候,不小心把/etc/profile文件改坏了(就是没配置对),在source /etc/profile后导致所有命令都不可用了.出现如下报错: -bash: xx ...
- Mocha
Mocha https://mochajs.org/#installation Mocha is a feature-rich JavaScript test framework running on ...
- Django2.1,Xadmin2.0下的问题记录
此篇博文长期更新…… 环境: Ubuntu18.04, Python3.6, Django2.1, Xadmin2.0 1. Xadmin添加用户小组件时报错:xadmin render() got ...
- Distance on the tree(数剖 + 主席树)
题目链接:https://nanti.jisuanke.com/t/38229 题目大意:给你n个点,n-1条边,然后是m次询问,每一次询问给你u,v,w然后问你从u -> v 的路径上有多少边 ...
- ActiveMQ的Destination高级特性
1. Composite Destinations 组合目的地 组合队列Composite Destinations : 允许用一个虚拟的destination代表多个destinations ...
- Easyui datalist 使用记录
仅简单记录下,资料相对比较少 官方给了一个很简单的例子,没啥用处,文档:http://www.jeasyui.com/documentation/datalist.php 学习要点: 1.追加行 $( ...
- 51nod--1069 Nim 游戏(博弈论)
题目: 有N堆石子.A B两个人轮流拿,A先拿.每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出N及每堆石子的数量 ...