ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ABC266 Ex - Snuke Panic (2D)

2022-08-30 13:32:39  阅读:208  来源: 互联网

标签:2D ch return leq int ll ABC266 Snuke va


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-x'+y-y'\leq t-t'\)
  • \(x'-x+y-y'\leq t-t'\)

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

  • \(t'-x'-y'\leq t-x-y\)
  • \(t'+x'-y'\leq t+x-y\)

那么你按照 \(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有