牛客小白月赛 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;
}
加油