[ARC101F] Robots and Exits
本文思路基本来自于这篇题解
在一个数轴上有 \(n\) 个 robot 和 \(m\) 个 exit。
每次操作可以把所有 robot 同时向左或向右,所有 robot 都到过 exit 之后停止操作。
求 robot 从 exit 溜走的方案数,两个方案不同当且仅当有一个 robot 从不同的 exit 离开。
现在我们将对一个 robot 进行研究。我们发现只有改变他 向左或向右的最大值 的移动才会对这个 robot 有效果。 然后将 robot 的路线放在二维坐标图上初值为 \((0,0)\) 横纵坐标,第 \(i\) 个 robot 距离它最近的两边 exit 的距离分别是 \(a_i\) \(b_i\),那么答案就取决于先碰到 \(x=a_i\) 还是 \(y=b_i\)。
将 robot 的坐标转换为 \((a_i-0.5,b_i-0.5)\)。那象对于所有 robot 的移动路线,如果 robot 的坐标在其下面那么将会在 左侧出口离开 如果在右面则会从右侧出口离开。
感性理解一下,这样的直线数就等价于卡在每个 robot 左边左上角的直线数,那转移方程显然
\[f_i=\Sigma_{a_j<a_i,b_j<b_i}f_j+1
\]
套路问题
#include<bits/stdc++.h>
#define RG register
#define LL long long
#define U(x, y, z) for(RG int x = y; x <= z; ++x)
#define D(x, y, z) for(RG int x = y; x >= z; --x)
#define update(x, y) (x = x + y >= mod ? x + y - mod : x + y)
using namespace std;
void read(){}
template<typename _Tp, typename... _Tps>
void read(_Tp &x, _Tps &...Ar) {
x = 0; char ch = getchar(); bool flg = 0;
for (; !isdigit(ch); ch = getchar()) flg |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
if (flg) x = -x;
read(Ar...);
}
inline char Getchar(){ char ch; for (ch = getchar(); !isalpha(ch); ch = getchar()); return ch;}
template <typename T> inline void write(T n){ char ch[60]; bool f = 1; int cnt = 0; if (n < 0) f = 0, n = -n; do{ch[++cnt] = char(n % 10 + 48); n /= 10; }while(n); if (f == 0) putchar('-'); for (; cnt; cnt--) putchar(ch[cnt]);}
template <typename T> inline void writeln(T n){write(n); putchar('\n');}
template <typename T> inline void writesp(T n){write(n); putchar(' ');}
template <typename T> inline void chkmin(T &x, T y){x = x < y ? x : y;}
template <typename T> inline void chkmax(T &x, T y){x = x > y ? x : y;}
template <typename T> inline T Min(T x, T y){return x < y ? x : y;}
template <typename T> inline T Max(T x, T y){return x > y ? x : y;}
inline void readstr(string &s) { s = ""; static char c = getchar(); while (isspace(c)) c = getchar(); while (!isspace(c)) s = s + c, c = getchar();}
inline void FO(string s){freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout);}
const int N = 1e5 + 10, mod = 1e9 + 7;
int n, m, a[N], b[N], cnt, un[N];
#define pii pair<int, int>
#define fi first
#define se second
pii node[N];
struct BIT {
int c[N];
#define lb(x) (x & -x)
inline void modify(int x, int p) {
for (; x <= cnt; x += lb(x))
update(c[x], p);
}
inline int query(int x) {
int res = 0;
for (; x; x -= lb(x))
update(res, c[x]);
return res;
}
} tr;
int main(){
//FO("");
read(n, m);
U(i, 1, n) read(a[i]);
U(i, 1, m) read(b[i]);
int tot = 0;
U(i, 1, n) {
int pos = lower_bound(b + 1, b + m + 1, a[i]) - b;
if (pos == 1 || pos > m) continue ;
node[++tot] = {a[i] - b[pos - 1], - (b[pos] - a[i])};
un[tot] = -node[tot].se;
}
sort(node + 1, node + tot + 1);
U(i, 1, n) node[i].se = -node[i].se;
sort(un + 1, un + tot + 1);
cnt = unique(un + 1, un + tot + 1) - un;
U(i, 1, tot) node[i].se = lower_bound(un + 1, un + cnt, node[i].se) - un + 1;
tr.modify(1, 1);
U(i, 1, tot) {
if (node[i].fi == node[i - 1].fi && node[i].se == node[i - 1].se) continue;
int t = tr.query(node[i].se - 1);
tr.modify(node[i].se, t);
}
writeln(tr.query(cnt));
return 0;
}