其他分享
首页 > 其他分享> > ABC266 Ex - Snuke Panic (2D)

ABC266 Ex - Snuke Panic (2D)

作者:互联网

ABC266 Ex - Snuke Panic (2D)

挺好的一道题(不过调了好久QAQ

方法一

比较暴力的做法。

首先,你容易想到一个 DP 状态:\(f(t,x,y)\) 表示在 \(t\) 时刻到达 \((x,y)\) 的最大收益。

转移为:

\[f(t,x,y)=\max\{f(t',x',y')|t'\leq t,y'\leq y,|x-x'|+y-y'\leq t-t'\} \]

后面的限制意思就是说你必须要在这么多时间里能够走这么多路程,因为已经有 \(t'\leq t,y'\leq y\),所以就不需要加绝对值了。

但是 \(x\) 还留着绝对值,不好处理,所以向把这个绝对值拆开。

因为 \(-|x-x'|\leq |x-x'|\),所以自然有 \(-|x-x'|+y-y'\leq t-t'\)。

这样就成功地把绝对值拆成了两个限制:

对它做一个变形(即移项使 \(x,y,t\) 在一边,\(x',y',t'\) 在一边),得到:

那么你按照 \(y\) 对它排一下序,只用考虑满足上面两个性质地最大值,用二维树状数组做就行了。

时间复杂度 \(O(n\log^2 n)\)。

方法二

前面的转化还是跟上面一样的。

你按 \(y\) 排完序以后可以考虑用 CDQ 分治来做。

现在考虑问题已经知道 \([l,mid]\) 的值,如何计算出 \([mid+1,r]\) 的值。

首先需要明确,因为已经按找 \(y\) 排序过了,所以所有 \([l,mid]\) 的 \(y\) 必然不大于 \([mid+1,r]\) 的 \(y\)。

也就是说,只需要考虑 \(t'-x'-y'\leq t-x-y\) 和 \(t'+x'-y'\leq t+x-y\) 的限制即可。

对于这两个限制,可以先对 \(t-x-y\) 值排序,这样就只剩一个限制了,然后用树状数组就可以做了。

时间复杂度 \(O(n\log^2 n)\),但是常数极小,比方法一不知道快多少倍。

注意:需要添加一个点 \((0,0,0,0)\),并且在树状数组计算的时候需要将初值设为 \(-\infty\),防止转移其他的。

反思

第一个思路比较简单,只需要将转移和限制在纸上清晰地列下来就行。

方法二地 CDQ 分治比较巧妙,需要用到一些奇技淫巧。

方法一的 code:

#include<bits/stdc++.h>
//#define JERRY_JIANG
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
inline int read() {
	int x = 0;
	bool f = 0;
	char ch = getchar();
	while(!isdigit(ch)) f |= ch == '-', ch = getchar();
	while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	return f ? -x : x;
}
inline void print(int x) {
	if(x < 0) return putchar('-'), print(-x);
	if(x >= 10) print(x / 10);
	putchar(x % 10 + '0');
}
inline int lowbit(int x) {return x & -x;}
bool Memst;
int n;
struct Data {
	int y, a, b, sz;
	bool operator < (const Data &x) const {
		if(y != x.y) return y < x.y;
		if(a != x.a) return a < x.a;
		if(b != x.b) return b < x.b;
		return sz < x.sz;
	}
};
vector<Data> datas;
vector<int> va, vb;
struct FenwickTree1D {
	int Mxn;
	unordered_map<int, ll> tree;
	FenwickTree1D() : Mxn(0){};
	FenwickTree1D(int n) : Mxn(n){};
	void update(int x, ll v) {
		while(x <= Mxn) {
			tree[x] = max(tree[x], v);
			x += lowbit(x);
		}
	}
	ll query(int x) {
		ll res = 0;
		while(x > 0) {
			res = max(res, tree[x]);
			x -= lowbit(x);
		}
		return res;
	}
};
struct FenwickTree2D {
	int Mxn, Mxm;
	vector<FenwickTree1D> tree;
	FenwickTree2D(int n, int m) : Mxn(n), Mxm(m), tree(n, FenwickTree1D(m)){};
	void update(int x, int y, ll v) {
		while(x <= Mxn) {
			tree[x].update(y, v);
			x += lowbit(x);
		}
	}
	ll query(int x, int y) {
		ll res = 0;
		while(x > 0) {
			res = max(res, tree[x].query(y));
			x -= lowbit(x);
		}
		return res;
	}
};
bool Memed;
int main(){
	fprintf(stderr, "%.3lf MB\n", (&Memst - &Memed) / 1048576.0);
	#ifdef JERRY_JIANG
		FILE *IN = freopen("input.in", "r", stdin);
		FILE *OUT = freopen("output.out", "w", stdout);
	#endif
	ios::sync_with_stdio(false); cin.tie(0);
	/* - input - */
	n = read();
	for(int i = 1; i <= n; i++) {
		int t = read(), x = read(), y = read(), sz = read();
		if(t - x - y >= 0 && t + x - y >= 0) {
			datas.push_back({y, t - x - y, t + x - y, sz});
			va.push_back(t - x - y); vb.push_back(t + x - y);
		}
	}
	double Timst = TIME;
	sort(datas.begin(), datas.end());
	sort(va.begin(), va.end());
	va.resize(unique(va.begin(), va.end()) - va.begin());
	sort(vb.begin(), vb.end());
	vb.resize(unique(vb.begin(), vb.end()) - vb.begin());
	FenwickTree2D T((int)va.size() + 1, (int)vb.size() + 1);
	ll ans = 0;
	for(int i = 0; i < (int)datas.size(); i++) {
		int y = datas[i].y, a = datas[i].a, b = datas[i].b, sz = datas[i].sz;
		a = lower_bound(va.begin(), va.end(), a) - va.begin() + 1;
		b = lower_bound(vb.begin(), vb.end(), b) - vb.begin() + 1;
		ll cur = T.query(a, b) + (ll)sz;
		ans = max(ans, cur);
		T.update(a, b, cur);
	}
	cout << ans << '\n';
	double Timed = TIME;
	fprintf(stderr, "%.3lf ms\n", Timed - Timst);
	return 0;
}
/*
author: Jerry_Jiang
start coding at 30/08/22 08:51
finish debugging at 30/08/22 09:53
*/

方法二的 code:

#include<bits/stdc++.h>
//#define JERRY_JIANG
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
inline int read() {
	int x = 0;
	bool f = 0;
	char ch = getchar();
	while(!isdigit(ch)) f |= ch == '-', ch = getchar();
	while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	return f ? -x : x;
}
inline void print(int x) {
	if(x < 0) return putchar('-'), print(-x);
	if(x >= 10) print(x / 10);
	putchar(x % 10 + '0');
}
inline int lowbit(int x) {return x & -x;}
bool Memst;
constexpr int N = 1e5 + 10;
int n;
pair<pii, pii> a[N];
pair<pii, int> b[N];
ll tree[N], dp[N];
void update(int x, ll v) {
	while(x < N) {
		tree[x] = max(tree[x], v);
		x += lowbit(x);
	}
}
ll query(int x) {
	ll res = -0x3f3f3f3f3f3f3f3f;
	while(x > 0) {
		res = max(res, tree[x]);
		x -= lowbit(x);
	}
	return res;
}
void solve(int l, int r) {
	if(l == r) {
		dp[l] += (ll)a[l].se.se;
		return;
	}
	int mid = (l + r) >> 1;
	solve(l, mid);
	vector<int> v;
	int tot = 0;
	for(int i = l; i <= r; i++) {
		int p = a[i].fi.se - a[i].fi.fi - a[i].se.fi, q = a[i].fi.se - a[i].fi.fi + a[i].se.fi;
		b[++tot] = make_pair(make_pair(p, q), i);
		v.push_back(q);
	}
	sort(b + 1, b + tot + 1);
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i = 1; i <= (int)v.size(); i++) tree[i] = -0x3f3f3f3f3f3f3f3f;
	for(int i = 1; i <= tot; i++) {
		int pos = lower_bound(v.begin(), v.end(), b[i].fi.se) - v.begin() + 1, id = b[i].se;
		if(id <= mid) update(pos, dp[id]);
		else dp[id] = max(dp[id], query(pos));
	}
	solve(mid + 1, r);
}
bool Memed;
int main(){
	fprintf(stderr, "%.3lf MB\n", (&Memst - &Memed) / 1048576.0);
	#ifdef JERRY_JIANG
		FILE *IN = freopen("input.in", "r", stdin);
		FILE *OUT = freopen("output.out", "w", stdout);
	#endif
	ios::sync_with_stdio(false); cin.tie(0);
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i].fi.se >> a[i].se.fi >> a[i].fi.fi >> a[i].se.se;
	sort(a + 1, a + n + 1);
	a[0].fi.fi = a[0].fi.se = a[0].se.fi = a[0].se.se = 0;
	memset(dp, -0x3f, sizeof(dp));
	dp[0] = 0;
	solve(0, n);
	ll ans = 0;
	for(int i = 1; i <= n; i++) ans = max(ans, dp[i]);
	cout << ans << endl;
	fprintf(stderr, "%.3lf ms\n", TIME);
	return 0;
}
/*
author: Jerry_Jiang
*/

标签:2D,ch,return,leq,int,ll,ABC266,Snuke,va
来源: https://www.cnblogs.com/Jerry-Jiang/p/16638939.html