0%

ARC101D

ARC101D Robots and Exits

Description

一维直线上有 个球和 个洞互不重叠。

你可以进行若干次操作,每次可以把所有球向左或向右移动 单位长度。

当球移动到洞的位置时,球就会掉进洞中。

你需要求出对于所有操作序列能得到球掉入洞里的方案数。对 取模。

两个方案不同当且仅当存在一个球在两种方案中掉进了不同的洞。

Sol

首先第一个洞左边和最后一个洞右边的球会掉进的洞是确定的,可以忽略。

其次所有球都会掉入它左边或右边的第一个洞。

考虑决定一个球掉入的洞的是其历史最左/最右位置达到其左/右的洞的先后,于是处理出每个球到达左/右的洞的距离

那么就可以理解为:一条从 出发的折线,每次只能向右或向上,碰到 的时候就会导致一个球向左/向右掉到洞里。

或者说:从 的左上/右下(均为不含)经过时就会掉到左/右的洞里。

然后我们发现我们发现在一个点左边的哪里经过都是一样的结果,于是只需要计算恰好经过的方案数。

然后就可以 DP 了: 表示以第 个点作为结尾的折线条数,则:

然后这个东西就是一个比较基础的二维偏序,离散化后开一个 BIT 即可。

时间复杂度

Code

借鉴了洛谷第一篇题解的写法(之前从来没想过可以把 DP 值存在 BIT 里最后 qry 一下就完了欸)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<bits/stdc++.h>
using std::vector;
typedef vector<int> vi;
typedef long long ll;
typedef std::array<int,2> pii;
#define all(a) a.begin(),a.end()
#define all1(a) a.begin()+1,a.end()
const int inf=(1<<30);
const int Mod=1e9+7;
template<typename Tp=int>inline Tp read(){Tp x(0);int op(0);char ch=getchar();while(ch<'0'||ch>'9')op|=(ch==45),ch=getchar();while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return op?-x:x;}

void cmod(int& x){x>Mod?x-=Mod:1;}

struct BIT{
private:
vi T;
int n;
public:
BIT(int _n=0){T.resize((n=_n)+1);}
void add(int x,int k){for(;x<=n;x+=(x&(-x)))cmod(T[x]+=k);}
int qry(int x){int ans=0;for(;x;x-=(x&(-x)))cmod(ans+=T[x]);return ans;}
};

int main(){
int n=read(),m=read();
vi a(n+1),b(m+3),X;
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=m;++i)b[i]=read();
b[m+1]=inf,b[m+2]=-inf;
std::sort(all1(b));
vector<pii> A={{0,0}};
for(int i=1;i<=n;++i){
int l=*(std::lower_bound(all1(b),a[i])-1),r=*std::upper_bound(all(b),a[i]);
if(l==-inf||r==inf)continue;
A.push_back({a[i]-l,r-a[i]}),X.push_back(r-a[i]);
}
int N=A.size()-1;
std::sort(all(X));X.erase(std::unique(all(X)),X.end());
for(int i=1;i<=N;++i)A[i][1]=std::lower_bound(all(X),A[i][1])-X.begin()+2;
std::sort(all1(A),[](pii x,pii y){return x[0]==y[0]?x[1]>y[1]:x[0]<y[0];});
BIT t(N+50);
t.add(1,1);
for(int i=1;i<=N;++i)if(A[i]!=A[i-1])t.add(A[i][1],t.qry(A[i][1]-1));
printf("%d\n",t.qry(N+10));
return 0;
}