比赛链接

点击打开链接

官方题解

点击打开链接

Problem A. Xor Battle

考虑维护使得最后一个玩家获胜的数字集合 S S S ,初始时, S = { 0 } S=\{0\} S={0} 。

考虑最后一个回合 i i i :
若该回合是 0 号玩家的回合,则有 S ′ = { x ∣ x ∈ S } ∪ { x ⊕ A i ∣ x ∈ S } S'=\{x\mid x\in S\}\cup\{x\oplus A_i\mid x\in S\} S′={x∣x∈S}∪{x⊕Ai​∣x∈S} ;
若该回合是 1 号玩家的回合,则若 A i ∈ S A_i\in S Ai​∈S ,则 S ′ = S S'=S S′=S ,否则, S ′ = ∅ S'=\varnothing S′=∅ 。

这是因为 S S S 是一个包含 0 0 0 的线性空间,因此若 A i ∉ S A_i\notin S Ai​∈/​S ,则对于所有 x ∈ S x\in S x∈S ,有 x ⊕ A i ∉ S x\oplus A_i\notin S x⊕Ai​∈/​S 。
那么,维护 S S S 的线性基,支持插入和询问某个元素是否在 S S S 中即可。

时间复杂度 O ( T N L o g V ) O(TNLogV) O(TNLogV) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 205;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
ll a[MAXN], b[MAXN], bit[MAXN];
char s[MAXN];
void ins(ll x) {for (int i = 60; i >= 0; i--)if (x & bit[i]) {if (b[i] == 0) {b[i] = x;break;}x ^= b[i];}
}
bool query(ll x) {for (int i = 60; i >= 0; i--)if (x & bit[i]) x ^= b[i];return x == 0;
}
int main() {int T; read(T);while (T--) {int n; read(n);for (int i = 1; i <= n; i++)read(a[i]);scanf("\n%s", s + 1);for (int i = 0; i <= 60; i++)b[i] = 0, bit[i] = 1ll << i;bool win = false;for (int i = n; i >= 1; i--) {if (s[i] == '0') ins(a[i]);else win |= !query(a[i]);}if (win) puts("1");else puts("0");}return 0;
}

Problem B. 01 Unbalanced

考虑将 0 看做 − 1 -1 −1 ,将 1 看做 + 1 +1 +1 ,求出各个位置的前缀和 S i ( 0 ≤ i ≤ N ) S_i\;(0\leq i\leq N) Si​(0≤i≤N) 。
可以发现,问题要求我们最小化 S i S_i Si​ 集合的极差。

考虑枚举 S i S_i Si​ 集合的最小值 M i n Min Min ,保证 S i S_i Si​ 均 ≥ M i n \geq Min ≥Min 的情况 下最小化最大值 M a x Max Max 。
则应当首先将所有的 ? 替换为 1 ,若此时,仍然存在 S i < M i n S_i<Min Si​<Min ,则显然不存在合法解。
否则,可以发现从前到后贪心地决定是否将一个 ? 修改为的 1 变成 0 是最优的。
则可以通过预处理 S i S_i Si​ 后缀最小值的方式 O ( N ) O(N) O(N) 解决该问题。

记 S i S_i Si​ 集合最小值的最大值为 M M M ,枚举 M i n = M , M − 1 , M − 2 , … Min=M,M-1,M-2,\dots Min=M,M−1,M−2,… 可以得到一个 O ( N 2 ) O(N^2) O(N2) 的做法。观察贪心的过程,可以发现 M i n = x − 2 Min=x-2 Min=x−2 的解不会优于 M i n = x Min=x Min=x 的解,从而可以只枚举 M i n = M , M − 1 Min=M,M-1 Min=M,M−1 ,降低时间复杂度。

时间复杂度 O ( N ) O(N) O(N) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
char s[MAXN];
int n, a[MAXN], sMin[MAXN]; bool b[MAXN];
void init() {for (int i = 1; i <= n; i++) {if (s[i] == '0') a[i] = a[i - 1] - 1;else a[i] = a[i - 1] + 1;if (s[i] == '?') b[i] = true;}sMin[n + 1] = n + 5;for (int i = n; i >= 0; i--)sMin[i] = min(sMin[i + 1], a[i]);
}
int work(int limit) {int mns = 0;for (int i = 1; i <= n; i++) {if (s[i] == '?' && sMin[i] - mns - 2 >= limit) {b[i] = false;mns += 2;} a[i] -= mns;}int Max = 0;for (int i = 1; i <= n; i++)chkmax(Max, a[i]);return Max - limit;
}
int main() {scanf("%s", s + 1);n = strlen(s + 1);int ans = n + 5, tmp = 0;init(); chkmin(ans, work(sMin[0]));init(); chkmin(ans, work(sMin[0] - 1));cout << ans << endl;return 0;
}

Problem C. Range Set

首先,我们显然可以将整个序列染成 1 ,因此,不妨令 A ≤ B A\leq B A≤B 。

考虑一个结果序列 S S S ,判断其是否可以到达。
对于一个长度至少为 A A A 的全 0 区间,我们可以将其任意染成一种颜色。
对于一个长度至少为 B B B 的全 1 区间,我们可以将其任意染成一种颜色。

由此,若将长度至少为 A A A 的全 0 区间全部染成 1 后,存在长度至少为 B B B 的全 1 区间,则结果序列 S S S 可以被达到。反之,不难证明,结果序列 S S S 不能被达到。

那么,记 d p i , j dp_{i,j} dpi,j​ 表示长度为 i i i 的区间,结尾处极长的全 1 区间的长度为 j j j ,转移时枚举下一个 1 的位置,可以得到一个 O ( N 3 ) O(N^3) O(N3) 的做法。
观察转移形式,用部分和优化即可。

时间复杂度 O ( N 2 ) O(N^2) O(N2) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
const int P = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
int n, a, b, dp[MAXN][MAXN], two[MAXN];
int pd[MAXN][MAXN], aux[MAXN];
void update(int &x, int y) {x += y;if (x >= P) x -= P;
}
int main() {read(n), read(a), read(b);if (a < b) swap(a, b); two[0] = 1;for (int i = 1; i <= n; i++)two[i] = 2ll * two[i - 1] % P;dp[0][0] = 1;for (int i = 0; i <= n; i++) {if (i != 0) update(aux[i], aux[i - 1]);update(dp[i][1], aux[i]);for (int j = 1; j <= a; j++) {update(dp[i][j], pd[i][j]);update(pd[i + 1][min(j + 1, a)], pd[i][j]);}if (i == n) break;for (int j = 0; j <= a - 1; j++) {update(dp[i + 1][j + 1], dp[i][j]);update(aux[i + 2], dp[i][j]);if (i + b + 1 <= n) update(aux[i + b + 1], P - dp[i][j]);if (i + b + 1 <= n) update(pd[i + b + 1][min(j + b + 1, a)], dp[i][j]);if (n - i >= b) update(dp[n][min(j + n - i, a)], dp[i][j]);}}int ans = 0;for (int i = 1; i <= n; i++)update(ans, 1ll * dp[i][a] * two[n - i] % P);cout << ans << endl;return 0;
}

Problem D. Lamps and Buttons

考虑 Snuke 的最优策略,应当为:
随机操作一盏亮着的灯 x x x
若 p x = x p_x=x px​=x ,则 x x x 永远不会再次亮起,游戏结束, Snuke 失败。
若 p x ≠ x p_x\ne x px​​=x ,则若 p x p_x px​ 暗了下去,则可以再次操作 x x x ,使其亮起;若 p x p_x px​ 亮了起来, Snuke 可以转而操作 p x p_x px​ ,直至将 x x x 所在的置换环全部点亮。

由于排列 p p p 的随机性,我们可以认为 Snuke 每次随机都会操作最小的尚未操作的灯。

那么,一个排列合法当且仅当其满足如下条件:
令 t t t 表示最小的,使得 p t = t , t ≤ A p_t=t,t\leq A pt​=t,t≤A 的位置,若不存在,则令 t = A + 1 t=A+1 t=A+1 ,
对于所有 A + 1 ≤ x ≤ N A+1\leq x\leq N A+1≤x≤N , x x x 所在的置换环上存在一个 ≤ t − 1 \leq t-1 ≤t−1 的元素。

考虑如何计数,由于 N N N 较大,不妨考虑将置换环中 ≥ A + 1 \geq A+1 ≥A+1 的元素删去,考虑剩余的置换。
此时,在 t t t 之前,可能会有其他的满足 p x = x p_x=x px​=x 的自环,但在插入 ≥ A + 1 \geq A+1 ≥A+1 的元素后,这些自环将会被补足为一个至少二元的环。在枚举 t t t 后,我们需要知道两点:
( 1 ) (1) (1) 、满足所在置换环中存在 ≤ t − 1 \leq t-1 ≤t−1 的元素的位置个数 i i i
( 2 ) (2) (2) 、满足 ≤ t − 1 \leq t-1 ≤t−1 ,且 p t = t p_t=t pt​=t 的位置个数 j j j

考虑将 ≥ A + 1 \geq A+1 ≥A+1 的元素插入进置换的合法方案数,应当为
( N − A ) j ‾ × ( i + ( N − A − j ) − 1 ) N − A − j ‾ (N-A)^{\underline{j}}\times (i+(N-A-j)-1)^{\underline{N-A-j}} (N−A)j​×(i+(N−A−j)−1)N−A−j​

同时,对于所在置换环中不存在 ≤ t \leq t ≤t 的元素的 max ⁡ { 0 , N − i − 1 } \max\{0,N-i-1\} max{0,N−i−1} 个位置,其置换的形式是任意的,即有系数
max ⁡ { 0 , N − i − 1 } ! \max\{0,N-i-1\}! max{0,N−i−1}!

由此,我们可以设计动态规划,将上文的 i , j i,j i,j 计入状态。
转移时枚举最小的元素所在的置换环的大小,不难得到一个 O ( A 3 + N ) O(A^3+N) O(A3+N) 的解法。

观察转移,用部分和优化,时间复杂度降为 O ( A 2 + N ) O(A^2+N) O(A2+N) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e7 + 5;
const int MAXM = 5e3 + 5;
const int P = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
int fac[MAXN], inv[MAXN];
int power(int x, int y) {if (y == 0) return 1;int tmp = power(x, y / 2);if (y % 2 == 0) return 1ll * tmp * tmp % P;else return 1ll * tmp * tmp % P * x % P;
}
int binom(int x, int y) {if (y > x) return 0;else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P;
}
void update(int &x, int y) {x += y;if (x >= P) x -= P;
}
void init(int n) {fac[0] = 1;for (int i = 1; i <= n; i++)fac[i] = 1ll * fac[i - 1] * i % P;inv[n] = power(fac[n], P - 2);for (int i = n - 1; i >= 0; i--)inv[i] = inv[i + 1] * (i + 1ll) % P;
}
int n, m, dp[MAXM][MAXM], sum[MAXM][MAXM];
int func(int x, int y) {return 1ll * fac[x] * inv[x - y] % P;
}
int main() {read(n), read(m), init(n);dp[0][0] = 1, sum[0][0] = fac[m - 1];for (int i = 1; i <= m; i++)for (int j = 0; j <= i; j++) {update(dp[i][j], dp[i - 1][j - 1]);if (i >= 2) update(dp[i][j], 1ll * sum[i - 2][j] * inv[m - i] % P);sum[i][j] = (sum[i - 1][j] + 1ll * dp[i][j] * fac[m - i - 1]) % P;}int ans = 0;for (int i = 0; i <= m; i++)for (int j = 0; j <= i && j <= n - m; j++)update(ans, 1ll * dp[i][j] * fac[max(m - i - 1, 0)] % P * func(n - m, j) % P * func(i + (n - m - j) - 1, n - m - j) % P);cout << ans << endl;return 0;
}

Problem E. Fragile Balls

令 P P P 表示满足 A i ≠ B i A_i\ne B_i Ai​​=Bi​ 的球数。

考虑 C i = 1 C_i=1 Ci​=1 的情况,此时,答案或是 P P P ,或是 − 1 -1 −1 。

考虑对于每个球,建边 A i → B i A_i\rightarrow B_i Ai​→Bi​ ,由题目条件,各个点的入度均不为 0 0 0 。
定义连通块为将有向边看做无向边后,形成的连通块,则可以将连通块分为如下三类:
( 1 ) (1) (1) 、连通块中仅包含一个点,和一条指向自己的边
( 2 ) (2) (2) 、连通块中仅包含一个长度 ≥ 2 \geq 2 ≥2 的环,且不存在其它的边
( 3 ) (3) (3) 、连通块中的边数多于点数

可以发现,若存在第 ( 2 ) (2) (2) 类连通块,答案显然为 − 1 -1 −1 。
同时,若不存在第 ( 2 ) (2) (2) 类连通块,由各个点的入度均不为 0 0 0 的性质,我们可以按照拓扑序构造一组合法的方案。从而,答案为 P P P 当且仅当不存在第 ( 2 ) (2) (2) 类连通块。

考虑原有的问题,在 C i ≥ 1 C_i\geq 1 Ci​≥1 的情况下,即使存在第 ( 2 ) (2) (2) 类连通块,也可能有解。

我们可以将一个连通块外的球 x x x 移入第 ( 2 ) (2) (2) 类连通块,从而处理该连通块。
那么,记第 ( 2 ) (2) (2) 类连通块的个数为 X X X ,我们必然需要额外花费 X X X 步。

考虑球 x x x 的如下几种情况:
( 1 ) (1) (1) 、 x x x 在第 ( 1 ) (1) (1) 类连通块内,此时,若要将 x x x 移出,必须将另一个球移入 x x x 所在的位置,即将 x x x 所在的连通块看做第 ( 2 ) (2) (2) 类连通块处理。这会导致 X X X 增加 1 1 1 ,同时,我们也可以处理掉 C x − 1 C_x-1 Cx​−1 个连通块,总的效果是导致 X X X 减去 C x − 2 C_x-2 Cx​−2 ,并且额外花费 2 2 2 步。
( 2 ) (2) (2) 、 x x x 在第 ( 2 ) (2) (2) 类连通块内,我们可以在所在连通块被处理时将 x x x 移出,处理其余连通块,并在 x x x 移回时继续处理该连通块。总的效果是导致 X X X 减去 C x − 1 C_x-1 Cx​−1 ,没有额外花费步数。
( 3 ) (3) (3) 、 x x x 在第 ( 3 ) (3) (3) 类连通块内, A x = B x A_x=B_x Ax​=Bx​ ,效果是导致 X X X 减去 C x − 1 C_x-1 Cx​−1 ,并且额外花费 1 1 1 步。
( 4 ) (4) (4) 、 x x x 在第 ( 3 ) (3) (3) 类连通块内, A x ≠ B x A_x\ne B_x Ax​​=Bx​ ,效果是导致 X X X 减去 C x − 1 C_x-1 Cx​−1 ,没有额外花费步数。

同时,由于第 ( 1 ) , ( 2 ) (1),(2) (1),(2) 类连通块中的元素初始时是不能动的,若 X ≠ 0 X\ne 0 X​=0 ,必须存在至少一个属于情况 ( 3 ) , ( 4 ) (3),(4) (3),(4) 的球 x x x 。剩余的问题就变为了:给定若干个代价 ≤ 2 \leq 2 ≤2 的物品,求出使得物品总价值 ≥ X \geq X ≥X 的最小代价。排序后枚举代价为 1 1 1 的物品个数,用双指针计算答案即可。

时间复杂度 O ( M L o g M ) O(MLogM) O(MLogM) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int INF  = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
vector <int> res[3];
bool cycle[MAXN]; int x[MAXN], y[MAXN], c[MAXN];
int n, m, ind[MAXN], oud[MAXN], f[MAXN], s[MAXN];
int find(int x) {if (f[x] == x) return x;else return f[x] = find(f[x]);
}
void merge(int x, int y) {x = find(x), y = find(y);if (x != y) {f[y] = x;cycle[y] = false;s[x] += s[y];}
}
bool cmp(int x, int y) {return x > y;
}
int work(ll cnt, bool mode) {sort(res[0].begin(), res[0].end(), cmp);sort(res[1].begin(), res[1].end(), cmp);sort(res[2].begin(), res[2].end(), cmp);for (auto x : res[0]) cnt -= x;int ans = INF;if (mode == false) {if (res[1].empty()) return INF;cnt -= res[1][0];res[1].erase(res[1].begin());int cur = res[2].size(); ll sum = 0;for (auto x : res[2]) sum += x;while (cur >= 1 && sum - res[2][cur - 1] >= cnt)sum -= res[2][--cur];if (sum >= cnt) chkmin(ans, 1 + cur * 2);for (int i = 0; i < res[1].size(); i++) {cnt -= res[1][i];while (cur >= 1 && sum - res[2][cur - 1] >= cnt)sum -= res[2][--cur];if (sum >= cnt) chkmin(ans, 1 + (i + 1) + cur * 2);}return ans;} else {if (cnt <= 0) return 0;int cur = res[2].size(); ll sum = 0;for (auto x : res[2]) sum += x;while (cur >= 1 && sum - res[2][cur - 1] >= cnt)sum -= res[2][--cur];if (sum >= cnt) chkmin(ans, cur * 2);for (int i = 0; i < res[1].size(); i++) {cnt -= res[1][i];while (cur >= 1 && sum - res[2][cur - 1] >= cnt)sum -= res[2][--cur];if (sum >= cnt) chkmin(ans, (i + 1) + cur * 2);}return ans;}
}
int main() {read(n), read(m);for (int i = 1; i <= n; i++)f[i] = i, s[i] = 1, cycle[i] = true;for (int i = 1; i <= m; i++) {read(x[i]), read(y[i]), read(c[i]);merge(x[i], y[i]), oud[x[i]]++, ind[y[i]]++;}for (int i = 1; i <= n; i++)if (ind[i] != 1 || oud[i] != 1) cycle[find(i)] = false;int cnt = 0, ans = 0;for (int i = 1; i <= n; i++)if (f[i] == i) cnt += cycle[i] && s[i] >= 2;ll lft = cnt; bool key = false;for (int i = 1; i <= m; i++) {ans += x[i] != y[i];if (c[i] >= 2) {if (cycle[find(x[i])]) {if (s[find(x[i])] == 1) res[2].push_back(c[i] - 2);else res[0].push_back(c[i] - 1);} else {if (x[i] == y[i]) res[1].push_back(c[i] - 1);else {lft -= c[i] - 1;key = true;}}}}if (cnt == 0) {cout << ans << endl;return 0;} else {int tmp = work(lft, key);if (tmp == INF) cout << -1 << endl;else cout << ans + cnt + tmp << endl;}return 0;
}

Problem F. Division into Multiples

若 G = ( A , B ) ≠ 1 G=(A,B)\ne 1 G=(A,B)​=1 ,则可以令 A = A G , B = B G , C = C ( G , C ) A=\frac{A}{G},B=\frac{B}{G},C=\frac{C}{(G,C)} A=GA​,B=GB​,C=(G,C)C​ ,从而 ( A , B ) = 1 (A,B)=1 (A,B)=1 ;
若 G = ( A , C ) ≠ 1 G=(A,C)\ne 1 G=(A,C)​=1 ,则可以令 A = A G , C = C G , Y = ⌊ Y G ⌋ A=\frac{A}{G},C=\frac{C}{G},Y=\lfloor\frac{Y}{G}\rfloor A=GA​,C=GC​,Y=⌊GY​⌋ ,从而 ( A , C ) = 1 (A,C)=1 (A,C)=1
若 G = ( B , C ) ≠ 1 G=(B,C)\ne 1 G=(B,C)​=1 ,则可以令 B = B G , C = C G , X = ⌊ X G ⌋ B=\frac{B}{G},C=\frac{C}{G},X=\lfloor\frac{X}{G}\rfloor B=GB​,C=GC​,X=⌊GX​⌋ ,从而 ( B , C ) = 1 (B,C)=1 (B,C)=1 。
若 A ≥ C A\geq C A≥C 或 B ≥ C B\geq C B≥C ,则可以令 A = A % C , B = B % C A=A\%C,B=B\%C A=A%C,B=B%C 。

由此,问题转化为了 ( A , B ) = ( A , C ) = ( B , C ) = 1 (A,B)=(A,C)=(B,C)=1 (A,B)=(A,C)=(B,C)=1 的情况。
考虑方程 A x + B y ≡ 0 ( m o d C ) Ax+By\equiv 0\;(mod\;C) Ax+By≡0(modC) ,令 D = A × B − 1 D=A\times B^{-1} D=A×B−1 ,其中 B − 1 B^{-1} B−1 表示 B B B 在模 C C C 意义下的乘法逆元。则有通解:
{ x ≡ k y ≡ − k × D \left\{\begin{array}{rcl}x\equiv k\\y\equiv -k\times D\end{array} \right. {x≡ky≡−k×D​

注意到若存在两组解 ( x 0 , y 0 ) , ( x 1 , y 1 ) (x_0,y_0),(x_1,y_1) (x0​,y0​),(x1​,y1​) 满足 x 0 ≤ x 1 , y 0 ≤ y 1 x_0\leq x_1,y_0\leq y_1 x0​≤x1​,y0​≤y1​ ,则 ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​) 是不优的,我们不会使用。考虑求出在这个意义下,我们可能使用的那些解。

考虑如下子问题:给定 C × D C\times D C×D 的平面,从原点处出发,一束光线沿第一象限角平分线方向发射,达到 x = C x=C x=C 时,令 x = 0 x=0 x=0 ,达到 y = D y=D y=D 时,令 y = 0 y=0 y=0 。我们希望求出 y = D y=D y=D 上被光束击中时是前缀最大值的点。

考虑一个 D × D D\times D D×D 的正方形,可以发现,光束从任意点射入,都将从其对面的点射出,从而可以删去一个极大的,包含原点的正方形。利用类似欧几里得算法的过程重复删去正方形,我们可以得到所求的所有可能使用的解。它们在平面上形成了 O ( L o g V ) O(LogV) O(LogV) 段线段。

进一步思考上述算法的过程,我们还可以发现,这些解构成了一个下凸壳。
我们现在想要选择若干个向量,满足求和后,两维均小于等于 ( X , Y ) (X,Y) (X,Y) 。

由解集的凸性,我们一定只会使用将方向 ( X , Y ) (X,Y) (X,Y) 夹在中间的两种向量。
由此,二分答案,找到这两种向量,判断答案是否合法即可。

时间复杂度 O ( T L o g V ) O(TLogV) O(TLogV) 或 O ( T L o g 2 V ) O(TLog^2V) O(TLog2V) 。
以下代码实现的是 O ( T L o g 2 V ) O(TLog^2V) O(TLog2V) 的解法。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
void exgcd(int a, int b, int &x, int &y) {if (b == 0) {x = 1, y = 0;return;}int q = a / b, r = a % b;exgcd(b, r, y, x);y -= q * x;
}
int inv(int x, int p) {int a = 0, b = 0;exgcd(x, p, a, b);return (a % p + p) % p;
}
struct info {int x, y, c; } q[MAXN];
int top, a, b, c, x, y;
void work(int c, int d){q[top = 0] = (info) {0, 0, 0};int x, a = 1, b = 0;while (d != 0) {info tmp = q[top];q[++top] = (info) {tmp.x + c / d * a, tmp.y + c / d * d, c / d};for (int t = 1; t <= 2 && d != 0; t++){if (t == 1) b += c / d * a;else a += c / d * b;x = c % d, c = d, d = x;}}
}
ll func(ll x, ll y) {if (x < 0) return -1;else return x / y;
}
int main() {int T; read(T);while (T--) {read(a), read(x), read(b), read(y), read(c);int g = __gcd(a, b); a /= g, b /= g, c /= __gcd(c, g);g = __gcd(a, c), a /= g, c /= g, y /= g;g = __gcd(b, c), b /= g, c /= g, x /= g;a %= c, b %= c;if (c == 1) {printf("%d\n", x + y);continue;}int d = 1ll * a * inv(b, c) % c; work(c, d);if (q[top].x != c) q[++top] = (info) {c, c, 1};int ans = 0;for (int i = 1; i <= top; i++) {int lx = q[i - 1].x, rx = q[i].x;int ly = c - q[i - 1].y, ry = c - q[i].y;int dx = (rx - lx) / q[i].c, dy = (ly - ry) / q[i].c;int l = ans + 1, r = x + y;while (l <= r) {int mid = (0ll + l + r) / 2;ll s = func(x - 1ll * mid * lx, dx);ll t = func(y - 1ll * mid * ry, dy);if (s >= 0 && t >= 0 && s + t >= 1ll * q[i].c * mid) ans = mid, l = mid + 1;else r = mid - 1;}}printf("%d\n", ans);}return 0;
}

【AtCoder】AtCoder Grand Contest 045相关推荐

  1. 【USACO】2017 December Contest, Platinum题解

    [比赛经历] 大概顺利满分了,就是T2的代码比较难调. T2能够直观地反映出GDB和输出调试结合的优越性. [T1]Standing Out from the Herd [题目链接] 点击打开链接 [ ...

  2. 【AtCoder】AtCoder Grand Contest 046

    比赛链接 点击打开链接 官方题解 点击打开链接 Problem A. Takahashikun, The Strider 可以发现,任意时刻,玩家均位于以前两次操作路径的中垂线的交点上. 因此,答案即 ...

  3. 【AtCoder】AtCoder Grand Contest 041

    比赛链接 点击打开链接 官方题解 点击打开链接 Problem A. Table Tennis Training 若 A , B A,B A,B 奇偶性相同,则答案为 B − A 2 \frac{B- ...

  4. 【Atcoder】AtCoder Beginner Contest 174总结

    目录 A Air Conditioner B Distance C Repsept D Alter Altar E Logs F Range Set Query A B C D E F √ √ ● ○ ...

  5. 【Atcoder】Atcoder Beginner Contest 50

    战况:VP,1.2水题,3题一开始WA了,居然没有想到用快速幂,后来看了题解会了,T4没看.目前ABC已补.缺D. T1: A - Addition and Subtraction Easy 题意:求 ...

  6. 【递归】【线段树】【堆】AtCoder Regular Contest 080 E - Young Maids

    给你一个1~n的排列p,n是偶数,每次从中任选一对相邻的数出来,插到排列q的开头,如此循环,问你所能得到的字典序最小的排列q. 我们先确定q开头的两个数q1,q2,q1一定是p的奇数位的最小的数,而q ...

  7. 【arc075f】AtCoder Regular Contest 075 F - Mirrored

    题意 给定一个数x,问有多少个正整数y,使得rev(y)-y==x 其中rev(x)表示x按位翻转之后得到的数. x<=1e9 做法 首先通过打表发现,这个答案不会很大. 这就说明解相当地松弛. ...

  8. 【题解】Atcoder ARC#90 F-Number of Digits

    Atcoder刷不动的每日一题... 首先注意到一个事实:随着 \(l, r\) 的增大,\(f(r) - f(l)\) 会越来越小.考虑暴力处理出小数据的情况,我们可以发现对于左端点 \(f(l) ...

  9. 【题解】AtCoder ARC128D - Neq Neq

    题意:有 NNN 个球排成一行,编号为 111 到 NNN . 第 iii个球上写着一个数AiA_iAi​. 你可以执行下列操作任意多次: 选三个相邻的位置 xxx, yyy, zzz (1≤x< ...

最新文章

  1. ELK 搭建 TB 级海量日志监控系统,这个太强了!
  2. postmessage and sendmessage
  3. mysql实习生笔试题_2014阿里实习生面试题MySQL如何实现索引的
  4. NumPy (6)-结构化数据类型数组
  5. 使用C++实现YUV格式图像与RGB格式图像之间相互转换
  6. 华为畅享10评测:4800万超清夜景 多方全能的千元实力派手机
  7. 回归预测值预测区间_机器学习之线性回归概述
  8. 设计模式之——抽象工厂模式
  9. python : sha256 、ripemd160
  10. a标签实现下载文件功能
  11. JDK11下载与安装
  12. 思维导图怎么画简单又漂亮?思维导图制作方法分享
  13. xmapp教程及扩展
  14. PHP 之建行龙支付-被扫(商家扫码客户二维码),扫码枪使用
  15. java 枚举Enum
  16. windows下使用curl命令
  17. mac下面如何修改只读文件
  18. Icpc 焦作站现场赛 E 题解
  19. iOS如何完成蓝牙打印机功能
  20. org.springframework.scheduling.quartz.CronTriggerBean 配置

热门文章

  1. 没想到,错误的单例写法,让 RabbitMQ 大量超时导致程序挂死!
  2. Mysql数据恢复---闪回恢复
  3. Linux中压缩解压工具使用
  4. HTML提供的5种空格实体(nbsp`;`ensp`; `emsp`;` thinsp`; `zwnj`;`zwj`;)
  5. Java面试之——Tomcat
  6. python绘制曲线、散点图
  7. 深度学习(二十)基于Overfeat的图片分类、定位、检测
  8. 30分钟学会XAML
  9. 三千年读史,不外乎功名利禄。九万里悟道,终归诗酒田园。
  10. 蒲公英内测分发平台使用体验