1 条题解
-
0
自动搬运
来自洛谷,原作者为

言琢დ
“我会成为这里的主宰,清除掉整片土地上的一切障碍,只留下我跟那一堆白骨,她永远不朽,而我不死不灭。”搬运于
2025-08-24 22:34:08,当前版本为作者最后更新于2021-10-20 20:23:53,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
出题人题解。
E 黄牛の争
数学模型
考虑优化 Special Judge 中
win函数部分的暴力,首先记-
表示 击败 所需回合数;
-
表示 击败 所需回合数。
那么:
-
如果 是先手,仅需 即可击败 ;
-
如果 是后手,则需 才能击败 。
据此,可以得到 击败 的条件:
$$\left\lceil\frac{A}{b}\right\rceil+[b<a]\le\left\lceil\frac{B}{a}\right\rceil $$那么 的判定胜负的代码:
bool win(int a, int b, int c, int d){ return (b + c - 1) / c + (c < a) <= (a + d - 1) / a; }
下面开始分析每个子任务的得分方式。
Subtask 1
枚举上限 ,考虑优化:
-
只需要能击败 ,因此 的枚举上限应为 。
-
必须输给 ,因此 的枚举上限应为 。
Subtask 2
固定 之后, 越大 越强, 越小 越弱。
所以 的合法取值一定在一个区间 上,可以考虑二分 。
Subtask 3, 5
留给一些正确性可能看起来很对的奇怪做法。
(比如某不知名 的做法)Subtask 4
那么这部分分显然是希望我们给出一个 的线性做法。
考虑如果我们确定了 ,继续推一推式子(其实也就是挪一挪系数),得到:
$$b\times\left(\left\lfloor\dfrac{B}{c}\right\rfloor+[c<b]\right)~\le~C~\le~\left(\left\lfloor\dfrac{A}{c}\right\rfloor-[a<c]\right)\times a+a-1 $$据此就可以 求出 的值。
Subtask 6
考虑一种更快的枚举 的方式。
由于 作为分母,它的取值只影响
$$\left\lceil\dfrac{A}{c}\right\rceil,\left\lceil\dfrac{B}{c}\right\rceil $$的取值,我们可以整除分块枚举 的取值。
一种上取整转下取整的办法:
$$\left\lceil\dfrac{p}{q}\right\rceil=\left\lfloor\dfrac{p-1}{q}\right\rfloor+1 $$另外,朴素的整除分块只枚举到
但是我们的 应当一直到
处都可能具有贡献。
所以我们考虑根据题意分成两段枚举,第一段使用朴素的整除分块。
第二段枚举 之间的答案贡献部分即可。
std
//E1 #include<cstdio> int init(){ char c = getchar(); int x = 0, f = 1; for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * f; } void print(int x){ if (x < 0) x = -x, putchar('-'); if (x > 9) print(x / 10); putchar(x % 10 + '0'); } bool win(int a, int b, int c, int d){ return (b + c - 1) / c + (c < a) <= (a + d - 1) / a; } int mn(int a, int b){ return a < b ? a : b; } int mx(int a, int b){ return a > b ? a : b; } int main(){ int q = init(); while (q--) { int a = init(), A = init(), b = init(), B = init(); if (win(b, B, a, A)) { puts("-1 -1"); continue; } bool flag = 1; for(int x = 1; x <= 100; ++x) for(int y = 1; y <= 100 && flag; ++y) if (x != a && x != b && win(b, B, x, y) && win(x, y, a, A)) flag = 0, print(x), putchar(' '), print(y), putchar('\n'); if(flag) print(-1), putchar(' '), print(-1), putchar('\n'); } } //E2 #include<cstdio> #define int long long int init(){ char c = getchar(); int x = 0, f = 1; for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * f; } void print(int x){ if (x < 0) x = -x, putchar('-'); if (x > 9) print(x / 10); putchar(x % 10 + '0'); } bool win(int a, int b, int c, int d){ return (b + c - 1) / c + (c < a) <= (a + d - 1) / a; } int mn(int a, int b){ return a < b ? a : b; } int mx(int a, int b){ return a > b ? a : b; } signed main(){ int q = init(); while (q--) { int a = init(), A = init(), b = init(), B = init(); int MAX = mn(mx(1 + b, B), mx(a, A) - 1); int M = mx(mx(a, A), mx(b, B)); if (!win(a, A, b, B) || (B > A && b > a)) { puts("-1 -1"); continue; } bool flag=1; for (int c = 1; c <= MAX; ++c) { if (c == a || c == b) continue; int l = 1, r = (M - 1) * (M - 1), ans = -1; if (c > a) r = A - 1; if (c < b) l = B + 1; while (l <= r) { int mid = l + r >> 1; if (!win(c, mid, a, A)) r = mid - 1; else if (!win(b, B, c, mid)) l = mid + 1; else { ans = mid; break; } } if (ans != -1) { print(c), putchar(' '), print(ans), putchar('\n'); flag = 0; break; } } if (flag) puts("-1 -1"); } } //E3 #include<cstdio> #define int long long int init(){ char c = getchar(); int x = 0, f = 1; for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * f; } void print(int x){ if (x < 0) x = -x, putchar('-'); if (x > 9) print(x / 10); putchar(x % 10 + '0'); } bool win(int a, int b, int c, int d){ return (b + c - 1) / c + (c < a) <= (a + d - 1) / a; } int a, A, b, B; int ok(int c){ if (c == a || c == b) return 0; int l = b * (B / c + (c < b)), r = (A / c - (a < c)) * a + a - 1; if (l > r) return 0; return l + 1; } int mn(int a, int b){ return a < b ? a : b; } int mx(int a, int b){ return a > b ? a : b; } signed main(){ int t = init(); for (int i = 1; i <= t; ++i) { a = init(), A = init(), b = init(), B = init(); if (!win(a, A, b, B) || (B > A && b > a)) { puts("-1 -1"); continue; } --A, --B; int c = 0, C; if (!ok(a + 1) && !ok(b + 1)) { for (int i = 1; i <= mx(A, B); ++i) if (ok(i)) { c = i, C = ok(i); break; } } else { if (ok(a + 1)) c = a + 1, C = ok(a + 1); if (ok(b + 1)) c = b + 1, C = ok(b + 1); } if (c) print(c), putchar(' '), print(C), putchar('\n'); else puts("-1 -1"); } } //E4 #include<cstdio> #define int long long int init(){ char c = getchar(); int x = 0, f = 1; for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * f; } void print(int x){ if (x < 0) x = -x, putchar('-'); if (x > 9) print(x / 10); putchar(x % 10 + '0'); } bool win(int a, int b, int c, int d){ return (b + c - 1) / c + (c < a) <= (a + d - 1) / a; } int a, A, b, B; int ok(int c){ if (c == a || c == b) return 0; int l = b * (B / c + (c < b)), r = (A / c - (a < c)) * a + a - 1; if (l > r) return 0; return l + 1; } int mn(int a, int b){ return a < b ? a : b; } int mx(int a, int b){ return a > b ? a : b; } signed main(){ int t = init(); for (int i = 1; i <= t; ++i) { a = init(), A = init(), b = init(), B = init(); if (!win(a, A, b, B) || (B > A && b > a)) { puts("-1 -1"); continue; } --A, --B; int c = 0, C; if (!ok(a + 1) && !ok(b + 1)) { for (int i = 1; i <= A && i <= B; i = mn(A / (A / i), B / (B / i)) + 1) if (ok(i)) { c = i, C = ok(i); break; } for (int i = mn(A, B) + 1; i <= mx(A, B); i = mx(A, B) / (mx(A, B) / i) + 1) if (ok(i)) { c = i, C = ok(i); break; } } else { if (ok(a + 1)) c = a + 1, C = ok(a + 1); if (ok(b + 1)) c = b + 1, C = ok(b + 1); } if (c) print(c), putchar(' '), print(C), putchar('\n'); else puts("-1 -1"); } } -
- 1
信息
- ID
- 6488
- 时间
- 1000~5000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者