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\) 轴上的基向量:
再和原先的基向量 \((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;
}