【ARC101F】Robots and Exits 树状数组优化DP
ARC101F Robots and Exits 树状数组
有 $ n $ 个机器人和 $ m $ 个出口。这 $ n $ 个机器人的初始位置是 $ a_1,a_2.....a_n $ ,这 $ m $ 个出口的位置是 $ b_1,b_2.....b_m $ 。你每次可以让所有机器人往左走一步或往右走一步。当一个机器人所在的位置有一个出口时,这个机器人就会从这个出口出去。问你有多少种让机器人全部离开的方案。两种方案不同当且仅当有至少一个机器人从不同的出口出去。 $ n,m≤100000 $
$ solution: $
首先我们可以将所有在最左端出口以左,最右端出口以右的机器人删掉,他们的最终出口只有一个,不影响答案。
然后我们考虑对于机器人 $ i $ ,它到左边距离它最近的出口的距离为 $ x_i $ ,如果我们往左移的距离超过 $ x_i $ 机器人就会掉进左边这个出口 ;同理设它到右边距离它最近的出口的距离为 $ y_i $ ,如果我们往右移的距离超过 $ y_i $ 机器人就会掉进右边这个出口。为了方便理解,我们先将它放到平面上:

我们考虑这个二维平面的意义:如果我们单纯将机器人左移或右移一个单位,会做很多无用功。但是我们发现,如果我们设 $ (l,r) $ 表示我向左移的最远 $ l $ 步 和向右移的最远 $ r $ 步 ,我们只有将最远步数向外扩展+1,才可能会有机器人掉进出口。而我们如果将这个步数也放到平面上,因为 $ l $ 和 $ r $ 的不断增大,会产生一个折线(如下图一)。我们发现这个折线如果经过某些平行于 $ y $ 轴的直线,它所代表的实际意义就是:对应的机器人会在这条折线与直线相交的时候掉入左边的出口(即当 $ l==x_i $ 时机器人 $ i $ 到达左边出口)

同理,我们发现这个折线如果经过某些平行于 $ x $ 轴的直线,其实际意义为:对应的机器人会在这条折线与直线相交的时候掉入右边的出口(即当 $ r==y_i $ 时机器 $ i $ 到达右边的出口)(如下图二)

我们再仔细观察一下这个平面所能带给我们的信息,我们发现这样一个性质:折线单调递增。折线通过竖直的直线时(继续上图一),这个点一定在折线上方,对应的机器人从左边出口掉落;折线通过水平的直线时(继续上图二),这个点一定在折线下方,对应的机器人从右边出口掉落。这是一个十分有用的性质!因为我们的所求的方案不同,当且仅当有至少一个机器人从不同的出口出去,我们将这个题意转入平面中,意思就是折线上下的点集不同!
然后我们的DP就要登场辣!(好吧,请忽略这个中二病语气)首先我们要设出状态,我们可以根据折线每一次向上走设出状态(只有向上走越过某一条直线才会改变状态),我们设 $ f[i] $ 表示折线最后一次向右转后第一个包括的点为 $ i $ 的所有方案(这个点是所有折线下面的点里最高的点,有多个最高就取最左端的点)。这样设状态不会重复,我们需要仔细思考这样设状态的意义。(这个状态转移是比较难想到的!因为要不重不漏)
然后我们考虑怎么转移:以下图为例,我们的 $ f[i] $ 是包括了点 $ i $ 的,我们如果让折线在包括点 $ i $ 后将状态转移到 $ j $ ,我们必须保证移动过程中 $ j $ 是折线最后一次向右转后第一个包括的点。于是我们可以继续向右移直到这个点 $ j $ 的竖直直线,我们立即向上转,再用折线从 $ j $ 水平直线越过后立即向右转。如下图: $ f[1] $ 可以转移到 $ f[5],f[4],f[3] $ ,所有在它右上方的点都可以!(这样的实际意义就是,我们原本 $ f1 $ 中在点1直接向右转就不往上了,意义是点345都从左边出口出去,现在我们用折线包括后点345分别变成从右边出口出去!)

同理,我们的 $ f2 $ 也可以转移到所有在它右上方的点!

于是我们发现转移方程其实就是这样:每个点的状态可以通过它左下方的点转移过来(我们上面讨论的是转移过去)
$ f[i]=f[j]+1 \quad (x_i>x_j,y_i>y_j) $
这个可以用树状数组维护,我们先将所有点按照纵坐标为第一关键字从低到高排序,横坐标为第二关键字从右到左(从右到左是为了方便转移不重复,注意上面转移方程是两个小于号,我们平面里同一高度左边的点不能转移到右边,它不满足保证移动过程中 $ i $ 是折线最后一次向右转后第一个包括的点,第一个仍旧是原来那一个)。具体实现时,我们直接按顺序枚举所有点的状态,然后按照横坐标将每个点 $ i $ 对应的 $ f[i] $ 存进树状数组,因为我们的枚举的高度从低到高,那么后面我查询时直接在树状数组上查找横坐标-1的前缀和,即可完成转移!
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
const int mod=1e9+7;//998244353;
int n,m;
int tt,ans=1; //注意赋了初值1
int a[500005];
int b[500005];
int k[500005]; //离散化
int f[500005]; //计数
int tr[500005]; //树状数组
struct su{
int x,y;
inline bool operator <(const su &z)const{
if(y==z.y)return x>z.x;
return y<z.y;
}
}s[500005];
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
inline void add(int x,int v){ //树状数组加入
for(;x<=tt;x+=x&-x) (tr[x]+=v)%=mod;
}
inline int ask(int x){ //树状数组查询
rg res=0;
for(;x;x-=x&-x) (res+=tr[x])%=mod;
return res;
}
int main(){
//freopen("robot.in","r",stdin);
//freopen("robot.out","w",stdout);
n=qr(); m=qr();
for(rg i=1;i<=n;++i) a[i]=qr();
for(rg i=1;i<=m;++i) b[i]=qr(); //已经按顺序排序
for(rg i=1,j=1;i<m&&j<=n;++i){
while(j<=n&&a[j]<=b[i])++j; //找到中间的第一个机器人
if(j>n)break;
while(j<=n&&a[j]<b[i+1]){ //遍历所有在中间的机器人
k[++tt]=a[j]-b[i]; //k数组是用来离散化的
s[tt]=su{k[tt],b[i+1]-a[j]}; ++j; //记录左右距离
}
} sort(k+1,k+tt+1); //离散化
for(rg i=1;i<=tt;++i)
s[i].x=lower_bound(k+1,k+tt+1,s[i].x)-k; //离散化
sort(s+1,s+tt+1); //按纵坐标从小到大,横坐标从大到小
for(rg i=1;i<=tt;++i){
if(s[i].x==s[i-1].x&&s[i].y==s[i-1].y)continue; //去重!
f[i]=(ask(s[i].x-1)+1)%mod; //只有横坐标比它小的才可以转移
ans=(ans+f[i])%mod; //计入答案
add(s[i].x,f[i]); //加入树状数组
}
printf("%d\n",ans);
return 0;
}
【ARC101F】Robots and Exits 树状数组优化DP的更多相关文章
- 【题解】ARC101F Robots and Exits(DP转格路+树状数组优化DP)
[题解]ARC101F Robots and Exits(DP转格路+树状数组优化DP) 先删去所有只能进入一个洞的机器人,这对答案没有贡献 考虑一个机器人只能进入两个洞,且真正的限制条件是操作的前缀 ...
- HDU 6240 Server(2017 CCPC哈尔滨站 K题,01分数规划 + 树状数组优化DP)
题目链接 2017 CCPC Harbin Problem K 题意 给定若干物品,每个物品可以覆盖一个区间.现在要覆盖区间$[1, t]$. 求选出来的物品的$\frac{∑a_{i}}{∑b_ ...
- Codeforces 946G Almost Increasing Array (树状数组优化DP)
题目链接 Educational Codeforces Round 39 Problem G 题意 给定一个序列,求把他变成Almost Increasing Array需要改变的最小元素个数. ...
- LUOGU P2344 奶牛抗议 (树状数组优化dp)
传送门 解题思路 树状数组优化dp,f[i]表示前i个奶牛的分组的个数,那么很容易得出$f[i]=\sum\limits_{1\leq j\leq i}f[j-1]*(sum[i]\ge sum[j- ...
- 【题解】Music Festival(树状数组优化dp)
[题解]Music Festival(树状数组优化dp) Gym - 101908F 题意:有\(n\)种节目,每种节目有起始时间和结束时间和权值.同一时刻只能看一个节目(边界不算),在所有种类都看过 ...
- Codeforces 909C Python Indentation:树状数组优化dp
题目链接:http://codeforces.com/contest/909/problem/C 题意: Python是没有大括号来标明语句块的,而是用严格的缩进来体现. 现在有一种简化版的Pytho ...
- BZOJ3594: [Scoi2014]方伯伯的玉米田【二维树状数组优化DP】
Description 方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美. 这排玉米一共有N株,它们的高度参差不齐. 方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感 ...
- Codeforces 629D Babaei and Birthday Cake(树状数组优化dp)
题意: 线段树做法 分析: 因为每次都是在当前位置的前缀区间查询最大值,所以可以直接用树状数组优化.比线段树快了12ms~ 代码: #include<cstdio> #include< ...
- BZOJ 3594: [Scoi2014]方伯伯的玉米田 (二维树状数组优化DP)
分析 首先每次增加的区间一定是[i,n][i,n][i,n]的形式.因为如果选择[i,j](j<n)[i,j](j<n)[i,j](j<n)肯定不如把后面的全部一起加111更优. 那 ...
随机推荐
- 清理docker 容器下面的log
1. docker info 找到docker root dir 2. go to /var/lib/docker 3. constainers 下面有每个容器的文件夹,-json.log 结尾的为L ...
- 十九、RF接口测试汇总(一)
搭建项目:转自 http://chuansong.me/n/1858477 A.请求方式为get请求 方式一:导入RequestsLibrary库,get request [ alias | ...
- Vue知识整理15:组件注册
采用局部注册组件: 将代码放在vue的一个实例中,而不是单列申明.
- C#SQL小结
对于c#获取Sql数据目前我采用的是 System.Data.SqlClient.SqlDataReader类. 主要用到如下API: SqlDataReader.Read():每次获取一行的数据,直 ...
- C 语言中的预处理
C 语言中以 # 开头的就是预处理指令,例如 #include . 预处理指令的用途 所有的预处理指令都会在 GCC 编译过程的预处理步骤解析执行,替换为对应的内容.在下一步编译过程中,看不到任何预处 ...
- 2017-0ctf-babyheap
fastbin attack + unsortedbin attack + __malloc_hook 的基础利用 题目下载 : https://uaf.io/assets/0ctfbabyheap ...
- 【HANA系列】SAP HANA SQL获取当前月的第一天
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL获取当前 ...
- TCP/IP协议-1
转载资源,链接地址https://www.cnblogs.com/evablogs/p/6709707.html
- 浅谈vue学习之组件通信
vue用组件化简化了我们编写代码的复杂度,组件之间经常会出现数据传递的情况,那么组件之间是怎样通信的呢? 使用props传递数据 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内 ...
- 前端 CSS 继承性和层叠性
CSS有两大特性:继承性和层叠性 前端 CSS的继承性 前端 CSS层叠性 CSS选择器优先级 前端 CSS 优先级 样式设置important