题解:AT_jsc2022_final_e Circular Sushi

· · 题解

可以证明答案 t = p/2^l,其中 p 是整数。

那么一个车能贡献当且仅当 a_i+ \dfrac{pv_i}{2^l} \equiv 0 \pmod {2^l},即 \dfrac{2^la_i + pv_i}{2^l} \equiv 0 \pmod {2^l}2^l a_i+pv_i \equiv 0 \pmod {2^{2l}}。这样就都是整数了。

然后如果重新设 a'_i=2^l a_i \bmod 2^{2l},t'=p,l'=2l 的话,就变成了有一个长度为 2^{l'} 的环,每个车初始在 a'_i,速度为 v_i,求一个整数 t' 使得此时在原点的车的价值和最大。这就又变成了最初的问题,只不过保证了答案为整数。

于是我们对于每个车,求出它第一次到原点的整数时刻 d_i,以及第二次到原点相较于第一次到原点的时间差 e_i

那么车 $i$ 能在 $t'$ 时刻到达原点当且仅当 $t' \bmod 2^{e'_i} = d_i$。即如果 $t'$ 的二进制下第 $e'_i$ 位为 $d_i$ 则会对答案贡献 $w_i$。 那很简单了。把所有 $(d_i,e'_i)$ 的限制对插入 Trie 里,然后只需要找一条叶子到根的链使得其价值和最大即可。 :::success[Code] ```cpp line-numbers #include <bits/stdc++.h> using namespace std; #define int long long const int N = 2e5 + 10; int n, m, a[N], v[N], w[N]; void exgcd(int a, int b, int &x, int &y) { if (!b) { x = 1, y = 0; } else { exgcd(b, a % b, y, x); y -= a / b * x; } } void work(int a, int &x, int b, int &y, int c) { int g = __gcd(a, b); exgcd(a, b, x, y); x *= c / g, y *= c / g; int dx = b / g, dy = a / g; if (dx < 0) dx = -dx, dy = -dy; int k; if (x < 0) k = (-x + dx - 1) / dx; else k = -x / dx; x += dx * k, y -= dy * k; } int idx; int tr[N * 60][2]; int res, sum[N * 60]; void dfs(int u, int s) { s += sum[u]; res = max(res, s); if (tr[u][0]) dfs(tr[u][0], s); if (tr[u][1]) dfs(tr[u][1], s); } signed main() { cin >> n >> m; for (int i = 1; i <= n; ++ i ) { cin >> a[i] >> v[i] >> w[i]; a[i] = a[i] * (1ll << m); } m = 1ll << m + m; for (int i = 1; i <= n; ++ i ) { int d, _; work(v[i], d, -m, _, -a[i]); int e = m / (v[i] & -v[i]); int k = __builtin_ctzll(e); int p = 0; for (int i = 0; i < k; ++ i ) { int w = d >> i & 1; if (!tr[p][w]) tr[p][w] = ++ idx; p = tr[p][w]; } sum[p] += w[i]; } dfs(0, 0); cout << res; return 0; } ```