Atcoder Regular Contest 101 F Robots and Exits 动态规划 树状数组 组合计数相关

版权声明:_ https://blog.csdn.net/lunch__/article/details/82770348

题意

  • 在数轴上有 n n 个机器人和 m m 个出口, 可以把所有机器人同时向左或者向右移动一个单位,一个机器人碰到出口就会离开,问有多少种方案数把让所有机器人都从出口出去,两个方案不同当且仅当存在一个机器人从不同的出口出去,答案对 1 e 9 + 7 1e9 + 7 取模

首先一个可以把初始在出口上和第一个出口左边和最后一个出口右边的机器人删去,因为他们出去的出口是确定了的

删去之后我们发现还是没有什么头绪 不如转化一下模型

记每个机器人到它左边出口的距离为 a i a_i , 到它右边的出口的距离为 b i b_i \

我们可以把每一个机器人用一个二维点对表示 ( a i , b i ) (a_i, b_i)

我们记 x x 为当前向左走的历史最大值, y y 为当前向右走的历史最大值,

每一个点 ( a i , b i ) (a_i, b_i) ,走到 x = a i x = a_i 或者 y = b i y = b_i 的时候这个机器人就已经离开了

那我们设 f [ i ] f[i] 为走到第 i i 个点后剩下全部往右走的方案数

那么 f [ i ] = j , x j < x i , y j < y i f [ j ] + 1 f[i] = \sum_{j, x_j < x_i, y_j < y_i}f[j] + 1

因为从第 i i 个点左下角的点可以向上或者向右到 i i

所以在加上之前的方案数还要加上向上走的方案

树状数组优化转移即可

注意方程的转移是严格小于,所以保证横坐标单调递增的前提下

也要保证纵坐标下降

Codes

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
const int mod = 1e9 + 7;

int n, m, cnt, a[N], b[N];
int tmpx[N], tmpy[N], c1, c2;

struct node {
	int x, y;
	bool operator < (const node &T) const {
		return x == T.x ? y > T.y : x < T.x;
	}
}A[N];

struct Fenwick_Tree {
	int s[N];
	void update(int x, int y) {for(; x <= c2; x += x & -x) (s[x] += y) %= mod;}
	int query(int x) {int res = 0; for(; x; x -= x & -x) (res += s[x]) %= mod; return res;}
}T;

void Init() {
	int x; priority_queue<int, vector<int>, greater<int>> q;
	cin >> n >> m;
	for(int i = 1; i <= n; ++ i) cin >> x, q.push(x);
	for(int i = 1; i <= m; ++ i) cin >> b[i]; n = 0;
	while(!q.empty()) {
		int k = q.top(), pos = lower_bound(b + 1, b + m + 1, k) - b; q.pop();
		if(k <= b[1] || k >= b[m] || b[pos] == k) continue;
		A[++ cnt].x = b[pos] - k; A[cnt].y = k - b[pos - 1];
		tmpx[++ c1] = A[cnt].x, tmpy[++ c2] = A[cnt].y;
	}
	sort(tmpx + 1, tmpx + c1 + 1), sort(tmpy + 1, tmpy + c2 + 1);
	c1 = unique(tmpx + 1, tmpx + c1 + 1) - tmpx - 1;
	c2 = unique(tmpy + 1, tmpy + c2 + 1) - tmpy - 1;
	for(int i = 1; i <= cnt; ++ i) {
		A[i].x = lower_bound(tmpx + 1, tmpx + c1 + 1, A[i].x) - tmpx;
		A[i].y = lower_bound(tmpy + 1, tmpy + c2 + 1, A[i].y) - tmpy;
	}
	sort(A + 1, A + cnt + 1);
}

void Solve() {
	int ans = 1;
	for(int i = 1; i <= cnt; ++ i) {
		if(A[i].y == A[i - 1].y && A[i].x == A[i - 1].x) continue;
		int now = T.query(A[i].y - 1) + 1;
		(ans += now) %= mod;
		T.update(A[i].y, now);
	}
	cout << ans << endl;
}

// $$f[i] = (\sum_{j = 1}^{i - 1} f[j]) + 1$$;

int main() {
#ifdef ylsakioi
	freopen("f.in", "r", stdin);
	freopen("f.out", "w", stdout);
#endif
	Init();
	Solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/82770348