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;
}