B: 牛牛战队的比赛地(二分做法)
题意:二维平面给定n个点,在x轴找一点使得到n个点距离的最大值最小。
思路:
我们可以将问题转化为在x轴找到一个圆心,使得该圆包含这n个点且半径最小,这样就变成了最小圆覆盖问题。有关于最大值最小此类问题,我们第一个想到的就应该是二分了,关键在于二分半径后如何check呢?
首先我们需要明白这样一个前提,也是解题的关键点:一个半径为R的圆,我们任意在圆上或圆内找一个点,也做半径为R的圆,那么这个圆一定会包含之前那个圆的圆心。
明白了这个,问题就easy了,我们将二分得到的半径R,把n个点都拿来做这样半径为R的圆,与x轴相交的部分,说明圆心可能落在这一范围内,然后我们只要看这些区域是否产生矛盾就好了。比如点1与x轴相交范围为[3,6],点2为[7,10],没有相交的部分,显然答案矛盾,即不存在半径为R的圆可以包含全部点。
#include#define x first #define y second #define d double using namespace std; const int N = 2e5 + 5; int n; pair p[N]; bool check(d o) { d l, mi = -1e18, ma = 1e18; for (int i = 1; i <= n; i++) { if (o < fabs(p[i].y)) return false; l = sqrt(o - p[i].y) * sqrt(o + p[i].y); ///等价于sqrt(o*o-p[i].y*p[i].y) mi = max(mi, p[i].x - l); ma = min(ma, p[i].x + l); } return mi <= ma; ///判断最大的左端点<=最小的右端点即可 } int main() { ios_base::sync_with_stdio(false); cin >> n; for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y; d l = 0, r = 1e18, mid; int t = 250; while (t--) { mid = (l + r) / 2.0; if (check(mid)) r = mid; else l = mid; } cout << fixed << setprecision(6) << r; return 0; }
D:牛牛与牛妹的约会 (贪心)
题解:我们先明确何时开根号走会更优,即:x - x^(1/3) > 1,解得x>2.3247179,因此我们贪心的按开根号走直到x<=2.3247179,同时维护最小值即可。
#includeusing namespace std; double cal(double x) { double l = 0, r = x, mid; int q = 50; while (q--) { mid = (l + r) * 0.5; if (mid * mid * mid >= x) r = mid; else l = mid; } return r; } int main() { int t; while (~scanf("%d", &t)) { while (t--) { double a, b; scanf("%lf%lf", &a, &b); double now = 0, ans = fabs(a - b); if (a >= 0) { while (a >= 2.3247179) { now += 1.0; a = cal(a); ans = min(ans, fabs(a - b) + now); } } else if (a < 0) { a = -a; b = -b; while (a >= 2.3247179) { now += 1.0; a = cal(a); ans = min(ans, fabs(a - b) + now); } } printf("%.9f\n", ans); } } return 0; }
E: Enjoy the game (博弈)
题解:多写几个就看出来了,是二次幂后手胜,否则先手胜。
#includeusing namespace std; int main() { int n; cin >> n; if (!(n & (n - 1))) ///判断是否为2次幂 cout << "Alice"; else cout << "Bob"; return 0; }
H:Hash (进制转化)
题解:
x%mod=p 不难得到 (x+mod)%mod=p
所以字符串加个mod就可以了,判一下长度是否还为6即可。
#includeusing namespace std; char s[20], a[105]; int mod, k, x; int main() { while (~scanf("%s%d", s, &mod)) { memset(a, 0, sizeof(a)); k = x = 0; for (int i = 0; i < 6; i++) x = x * 26 + s[i] - 'a'; ///转为10进制 x += mod; while (x) ///转回26进制 { a[++k] = x % 26; x /= 26; } if (k <= 6) { if (k < 6) ///长度不够6补a即可 k++; for (int i = k; i >= 1; i--) printf("%c", a[i] + 'a'); } else printf("-1"); puts(""); } return 0; }