Gym102769I Interstellar Hunter 题解

Gym102769I Interstellar Hunter 题解

题意:初始位置在 \((0,0)\) 点,现在有两种操作:

  • 操作 \(1\) :你获得一种能力向量 \((x,y)\) ,你可以从当前位置 \((a,b)\) 出发,沿着这个能力向量方向移动任意整数个单位,即可以从 \((a,b)\) 移动至 \((a+dx,b+dy)\)
  • 操作 \(2\) :在二维平面上的某一点 \((x,y)\) 上出现了一个价值为 \(w\) 的物品,如果你可以通过你当前拥有的能力向量移动至 \((x,y)\) 就可以获得该物品。

问最终你可以获得的最大价值是多少?

题解:本题的核心思想是对于一系列的能力向量 \((x_0,y_0),(x_1,y_1),(x_2,y_2),\cdots\) 的线性组合,我们都可以通过两个基向量 \((bx,by)\)\((dx,0)\) 的线性组合来得到,比较详细的证明请参考出题人在这个问题下的回答:

https://www.zhihu.com/question/426081900/answer/1535613903

因此我们需要维护这组基向量,使它能够表示所有能力向量的线性组合。

假设某一时刻,我们的基向量是 \((bx,by)\)\((dx,0)\) ,现在加入了一个新的能力向量 \((x,y)\) ,我们需要求解出新的基向量 \((bx',by')\)\((dx',0)\) 。首先容易求得 \(by'=\gcd(by,y)\) ,然后考虑 \(dx'\) ,利用 \((bx,by)\)\((x,y)\) 线性组合得到它们在 \(x\) 轴上的基向量:

\[\begin{aligned} \frac{y}{g}(bx,by)-\frac{by}{g}(x,y)=(\frac{1}{g}(y\cdot bx-by\cdot x),0) \end{aligned} \]

再和原先的基向量 \((dx,0)\) 组合就能得出 \(dx'=\gcd(dx,\frac{|y\cdot bx - by\cdot x|}{g})\)

最后,我们通过 \(exgcd\) 求出 \(bx'\) :由裴蜀定理可以得出,存在 \(a,b\in Z\) 使得 \(a\cdot y+b\cdot by=\gcd(y,by)\) ,因此我们可以通过 \(exgcd\) 求解该方程的一组解 \((a,b)\) 并得到:\(bx'=(a\cdot x+b\cdot bx)\bmod{dx'}\)

于是,我们就得到了一组新的基向量 \((bx',by')\)\((dx',0)\) ,最后注意一下向量某一维为零的特殊情况即可。

#include <bits/stdc++.h>
using namespace std;
 
template<typename T>
T exgcd(T x, T y, T& a, T& b) {
	if (!y) {
		a = 1, b = 0;
		return x;
	}
	T d = exgcd(y, x % y, b, a);
	b -= x / y * a;
	return d;
}
 
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int t; cin >> t;
	for (int kase = 1; kase <= t; kase++) {
		int n; cin >> n;
		long long ans = 0;
		long long bx = 0, by = 0, dx = 0;
		for (int i = 0; i < n; i++) {
			int op; cin >> op;
			long long x, y, w;
			if (op == 1) {
				long long a, b;
				cin >> x >> y;
				long long g = exgcd(y, by, a, b);
				dx = __gcd(dx, abs(y * bx - x * by) / g);
				by = g;
				bx = a * x + b * bx;
				if (dx) {
					bx = (bx % dx + dx) % dx;
				}
			}
			else {
				cin >> x >> y >> w;
				if (by && y % by == 0) {
					long long r = x - y / by * bx;
					if (dx && r % dx == 0 || dx == r) {
						ans += w;
					}
				}
				else if (by == 0) {
					if (bx && x % bx == 0 || bx == x) {
						ans += w;
					}
				}
			}
		}
		cout << "Case #" << kase << ": " << ans << '\n';
	}
	return 0;
}
posted @ 2020-10-24 18:52  st1vdy  阅读(425)  评论(0编辑  收藏  举报