牛客小白月赛 104(A、B、C、F)

牛客小白月赛 104

传送门:(0条未读通知) 牛客小白月赛104_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

A-小红购买装备(贪心)

只需要写一个结构体或者存tuple,然后按照战斗力降序排序,如果一致按照价格升序排序。遍历一遍数组找到比初始大并且能买下就返回答案即可

代码(c++):

#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>

#define ll long long

using namespace std;

const int N = 1e5 + 10;

struct T{
    ll u;
    ll v;
    ll w;
} a[N];

bool cmp(T A, T B){
    ll x = A.u + A.v, y = B.u + B.v;
    if(x != y) return x > y;
    else return A.w < B.w;
}

ll n, x, y, z, t;

int main()
{
    cin >> n >> x >> y >> z >> t;
    for(int i = 1;i <= n;i ++){
        cin >> a[i].u >> a[i].v >> a[i].w;
    }
    
    sort(a + 1, a + n + 1, cmp);
    
    ll ans = x + y, sum = t + z;
    for(int i = 1;i <= n;i ++){
        ll mx = a[i].u + a[i].v;
        if(mx > ans && sum >= a[i].w){
            ans = mx;
            sum = sum - a[i].w;
            break;
        }
    }
    cout << ans << endl;
    return 0;
}

B-小红招募英雄 (二项分布)

这道题是概率论的问题,当然只需要具备高中的概率论知识就行

很明显的二项分布 X~B(n, p)(公式就不写了,忘了可以去百度二项分布计算公式)

n题目已经给了抽10次么, n = 10。p 也給了就是 p4 + p5,求的是P(x >= 2)那不就是:1 - p(x<2)

只需要计算 p(x = 0) 和 p(x = 1)即可

代码(py):

p1, p2, p3, p4, p5 = map(float,input().split())

p = p4 + p5

x0 = (1 - p)**10
x1 = (1 - p)**9 * p * 10

ans = 1 - (x0 + x1)

print(ans)

C-小红打怪(二分)

碰到这种问题千万不要暴力去模拟,首先 n 已经是 100000, 在加上 a[i] 是 10 ^ 9,也就是最差要10 ^ 9轮,暴力肯定超时别去浪费时间

那肯定是要去优化,尽可能一次找到轮数,用二分。

这里虽然不满足单调性,但是还是可以用二分,因为只需要判断怪物是否全部死了即可。如果当前轮数没有全部打死就往跳到[mid + 1, r], 全部打死了就跳到 [l, mid]

这样的话复杂度就 log2 的 10^9 * 10 ^ 5 大概就是 3 * 10^6 那就没问题了

代码(c++):

#include <iostream>

#define ll long long

using namespace std;

const int N = 1e5 + 10;
int a[N], b[N];

int n;

bool check(int mid){
    ll f1 = mid, f2 = mid;
    for(int i = 1;i <= n;i ++) b[i] = max(a[i] - mid, 0);
    
    for(int i = 1;i < n;i ++){
        if(!f1) break;
        
        if(b[i] > 0 && b[i + 1] > 0){
            int x = min(b[i], b[i + 1]);
            if(f1 >= x){
                f1 -= x;
                b[i] -= x, b[i + 1] -= x;
            }
        }
    }
    
    ll sum = 0;
    for(int i = 1;i <= n;i ++) sum += b[i];
    
    return f1 + f2 >= sum;
}

int main()
{
    cin >> n;
    for(int i = 1;i <= n;i ++) cin >> a[i];
    
    int l = 1, r = 1e9;
    while(l < r){
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    
    cout << l << endl;
    
    return 0;
}

F.小红闯地下城 (lca)

lca知识点:Lca最近公共祖先(非常实用)-优快云博客

比赛中知道lca这个东西,但是题做得少没看出来这题怎么用lca

对于这个题目而言:我们可以首先先假设如果没有传送门的话最值是多少?

第一个点肯定要杀怪 体力:x - 1, 数量 :1

后续的话肯定是要把回到 1 这个点的路程考虑到,过去一个点消耗1, 杀怪消耗1,回来消耗1。 那么数量就是: min(n, (x - 1) / 3 + 1)

考虑有传送门的情况,就随便举个例子吧。红方框的代表互相传送用A,B表示吧

我们先计算一下能杀多少怪 (就是算有多少点) cnt = dep[A](A路径的点) + dep[B](B路径的点) - dep[lca(A, B)](把不是A 、B路径的点去掉)+ 1(起始点房间的怪物)

然后计算一下体力的消耗 cur = cnt(杀怪的数量) + dep[A](A路径) + dep[B](B路径) + 1(传送阵的消耗)

那么只需要去遍历一遍这个 a[i] 数组求一下最值即可

代码(c++):

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int N = 2e5 + 10;
int dep[N], fa[N][20], a[N];
vector<int> e[N];

int n, x;

void dfs(int u, int pa){
    dep[u] = dep[pa] + 1;
    fa[u][0] = pa;
    for(int i = 1; i < 20; i++){ 
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    
    for(auto v : e[u]){
        if(v == pa) continue;
        dfs(v, u);
    }
}

int lca(int A, int B){
    if(dep[A] < dep[B]) swap(A, B);
    for(int i = 19; i >= 0; i--){
        if(dep[A] - (1 << i) >= dep[B]){
            A = fa[A][i];
        }
    }
    if(A == B) return A;
    
    for(int i = 19; i >= 0; i--){
        if(fa[A][i] != fa[B][i]){
            A = fa[A][i];
            B = fa[B][i];
        }
    }
    return fa[A][0];
}

int main()
{
    cin >> n >> x;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1, u, v; i < n; i++){
        cin >> u >> v;
        e[u].push_back(v), e[v].push_back(u);
    }
    
    dep[0] = -1;
    dfs(1, 0);
    
    int ans = min(n, (x - 1) / 3 + 1);
    for(int i = 1; i <= n; i++){
        int A = i, B = a[i];
        if(A == B) continue;
        int pa = lca(A, B);
        int cnt = dep[A] + dep[B] - dep[pa] + 1;
        int cur = cnt + dep[A] + dep[B] + 1;
//         cout << A << " " << B << endl;
        if(x >= cur) ans = max(ans, min(n, cnt + (x - cur) / 3));
    }
    
//     for(int i = 1;i <= n;i ++){
//         cout << dep[i] << " ";
//     }
//     cout << endl;
    cout << ans << endl;
    return 0;
}

加油

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值