A、牛牛的三角形
方法一,枚举第一二三个点,判断任意两边之和都要大于第三边,时间复杂度
#include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) using namespace std; inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } const int N = 1e2 + 7; int a[N]; bool check(int a, int b, int c) { if (a + b > c && a + c > b && b + c > a) return true; return false; } int main() { int n = read(); for (int i = 1; i <= n; ++i) a[i] = read(); for (int i = 1; i < n - 1; ++i) for (int j = i + 1; j < n; ++j) for (int k = j + 1; k <= n; ++k) if (check(a[i] , a[j] , a[k])) { printf("%lld %lld %lld", a[i], a[j], a[k]); return 0; } puts("No solution"); return 0; }
方法二:先排序,再把连续的三个点判断,如果当前的三个升序数字不行,那么在后面一个数字,会比前面任何一个都大,更不满足任意两边大于第三边,放弃最前面最小的点。时间复杂度
#include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) using namespace std; inline int read() { int s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } const int N = 1e2 + 7; int num[N]; bool check(int a, int b, int c) { if (a + b > c && a + c > b && b + c > a) return true; return false; } int main() { int n = read(); for (int i = 1; i <= n; ++i) num[i] = read(); sort(num+1,num+1+n); for (int i = 1; i + 2 <= n; ++i) { if (check(num[i], num[i + 1], num[i + 2])) { printf("%d %d %d", num[i], num[i + 1], num[i + 2]); return 0; } } puts("No solution"); return 0; }
B、牛牛的鱼缸
鱼缸中的水只有2种状态,第一三角形,第二直角梯形。
先通过三角形相似,算出鱼缸如果没有阻挡的底记为x,如果这个底小于等于真正的底,直接按三角形计算即可。
如果大于,按照梯形公式,下底是给定的h,上底通过x-l和相似算得,高就是l。
#include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; inline int read() { int s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } const int N = 1e2 + 7; const int MOD = 1e9 + 7; int main() { double h = read(), l = read(), H = read(), L = read(); scanf("%lf%lf%lf%lf", &h, &l, &H, &L); double sl = h * L / H; if (sl <= l) { printf("%.8f\n", sl * h / 2); } else { double sh = H * (sl - l) / L; printf("%.8f\n", l * (sh + h) / 2); } return 0; }
C、牛牛的揠苗助长
二分+最小操作数
第一次拿到这个题目,我第一时间想法是枚举终点,二分天数,再去二分的时候跑最小,这样分析下来时间复杂度竟然到了
那我们必须换思路,或者改进算法。这个时候,我看到题目,我们如果二分天数的时候,如果对n取模,不就是确定了终点么?为什么还要去枚举终点。
所以这个地方除掉N的复杂度,总的复杂度就是
接下来就是二分法check函数的设计了,因为终点确定了,那我们知道,无论你多跑多少个轮回,中间轮回都是没用的,因为全部加一,看成全部不变就行了。
那么我们用一个a保持初始的高度,另开一个b保存在终点之前(包括终点)可以被额外高度加一的顶点和后序未被递增的顶点高度。
这个时候,问题就来到了如何通过这样的高度,找到最优解的高度。最终吧最优解高度下,和二分天数判断一下就行了。
我们知道,如果我们保证b有序(假设升序),如果b的点数是奇数,那么一定是中间的一个点高度下,花费最小。(下面配图)
如果b是偶数,中间两个点,假设高度是x4和x5,那么在 [x4,x5]中的全部高度,算到的答案都是一样的,并且最短,可以类比奇数情况(下面配图)
所以综上,在升序数组b中,按中位数(偶数取到左边高度或者右边高度不影响答案)节点的高度为最优解即可。
#include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; inline int read() { int s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } const int N = 1e5 + 7; const int MOD = 1e9 + 7; ll a[N], b[N]; int n; bool check(ll p) { ll sum = 0, mini = 1e18; for (int i = 1; i <= n; ++i) b[i] = a[i] + p / n + (p % n >= i ? 1 : 0); sort(b + 1, b + 1 + n); ll num1 = b[(n >> 1)+1]; ll ans = 0; for (int i = 1; i <= n; ++i) ans += abs(b[i] - num1); return ans <= p; } int main() { n = read(); for (int i = 1; i <= n; ++i) a[i] = read(); ll l = 0, r = 1e18, ans = 0; while (l <= r) { ll mid = r + l >> 1; if (check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } printf("%lld\n", ans); return 0; }