2022牛客寒假训练营(五)全部题解

11 篇文章 0 订阅
4 篇文章 0 订阅

A:疫苗小孩

题意 | 简单

  • 打疫苗一共可以打三针,且只有后两针接种才能提升手速,且一天最多只能打一针。后一针疫苗与前一针疫苗之间相隔k天对手速的提升最为明显,每偏离一天则效果会想应减少,每偏离一天则效果减少q的话,则后一针疫苗实际对人手速的影响为w - |k - p| * q
  • n天以后就是比赛,只考虑n天内疫苗的接种,但这n天中只能挑没有牛客比赛的日子去打疫苗
    n n n ≤ \leq 1 0 6 10^6 106 , 1 ≤ \leq k , w , q k,w,q k,w,q ≤ \leq 1 0 9 10^9 109

思路 | 贪心

  • 枚举第二针所在的位置pos ,二分找到离pos+k和pos-k最近的两个点计算最大贡献就可以啦

代码

#include <bits/stdc++.h>
#define int long long
#define pb push_back 
using namespace std;
const int maxn = 1e6 + 100;
int a[maxn];
void solve() {
    int n; string s; cin >> n >> s;
    s = '.' + s;
    int k, w, q;cin >> k >> w >> q;
    int cnt = 0;
    a[cnt] = n + 1;
    for (int i = 1; i <= n; i++)  if (s[i] == '0')a[++cnt] = i;
    a[cnt + 1] = n + 1;
    int maxx = 0;
    for (int i = 1; i <= cnt; i++) {
        int posb = a[i];
        int posa1 = a[lower_bound(a + 1, a + 1 + cnt, posb - k) - a - 1];
        int posa2 = a[lower_bound(a + 1, a + 1 + cnt, posb - k) - a];
        int posc1 = a[lower_bound(a + 1, a + 1 + cnt, posb + k) - a - 1];
        int posc2 = a[lower_bound(a + 1, a + 1 + cnt, posb + k) - a];
        if (posa1 < posb && posb <= a[cnt]) maxx = max(maxx, w - abs(posb + k - posa1) * q);
        if (posa2 < posb && posb <= a[cnt]) maxx = max(maxx, w - abs(posb + k - posa2) * q);
        if (posa1 < posb && posb < posc1 && posc1 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa1 + k - posb) * q - abs(posb + k - posc1) * q);
        if (posa1 < posb && posb < posc2 && posc2 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa1 + k - posb) * q - abs(posb + k - posc2) * q);
        if (posa2 < posb && posb < posc1 && posc1 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa2 + k - posb) * q - abs(posb + k - posc1) * q);
        if (posa2 < posb && posb < posc2 && posc2 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa2 + k - posb) * q - abs(posb + k - posc2) * q);
    }
    cout << maxx << endl;
}
signed main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int t; t = 1;
    while (t--) {
        solve();
    }
    return 0;
}


C:战棋小孩

题意 | 简单

  • 进行 n n n局游戏,每局游戏可以从两个英雄种选择一位,同时如果选择礼遇的话就会拥有再多两个英雄的选择。现在给出每局游戏的选将情况和结束后上榜需要的分数,和每局游戏结束后,排行榜上需要的分数,现在想直到通过能力合理排列并进行最优选择后,他最多因上榜而开心的次数。
    n , k , s n,k,s nks分别表示游戏局数,可使用礼遇的次数和初试分数
    0 ≤ \leq n , k n,k nk ≤ \leq 20 20 20

思路 | 枚举

  • 二进制枚举一下哪些位置需要使用礼遇,然后再排序一下(从大到小)就可以了(证明),按照累加是判断否可以得分

代码

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int maxn = 1e6 + 100;
const int mod = 1e9 + 7;
struct node {
    int val, maxval;
}a[maxn];
int p[maxn];
int b[maxn];
bool cmp(int a, int b) {
    return a > b;
}
void solve() {
    int n, k, s;
    cin >> n >> k >> s;
    int maxx = 0;
    for (int i = 0; i < n; i++) cin >> p[i];
    for (int i = 0; i < n; i++) {
        int aa, bb, c, d;
        cin >> aa >> bb >> c >> d;
        a[i].val = max(aa, bb);
        a[i].maxval = max(a[i].val, max(c, d));
    }
    for (int i = 0; i < (1 << n); i++) {
        int cnt = 0;
        for (int j = 0; j < n; j++) {
            if (i & (1 << j)) b[j] = a[j].maxval, cnt++;
            else b[j] = a[j].val;
        }
        if (cnt <= k) {
            sort(b, b + n, cmp);
            int sum = s;
            int ans = 0;
            for (int j = 0; j < n; j++) {
                sum += b[j];
                if (sum >= p[j]) ans++;
            }
            maxx = max(maxx, ans);
        }
    }
    cout << maxx << endl;
}
signed main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int t; t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

D:数位小孩

题意 | 简单

  • 给定一个区间 [ l , r l,r l,r] ,求这个区间内有多少个数字满足以下条件:

    1. 每相邻两个数位和为素数
    2. 其中至少一个数位为1
    3. 没有前导零
  • 0 ≤ \leq l , r l,r lr ≤ \leq 1 0 10 10^{10} 1010

思路 | 暴力

  • 因为数据范围不大,可以直接写一个dfs进行暴力寻找,把哪些数字可以相邻在一起的先预处理出来,然后就暴力开找就行啦

代码

#include <bits/stdc++.h>
#define int long long
#define pb push_back 
using namespace std;
const int maxn = 1e6 + 100;
typedef long long ll;
ll prime[1006];
bool sf[2006]; 
void sushu() {   
    ll num = 0; 
    memset(sf, true, sizeof(sf));
    sf[1] = false;
    sf[0] = false; 
    for (int i = 2; i < 1000; i++) {          
        if (sf[i]) prime[++num] = i;      
        for (int j = 1; j <= num; j++) {       
            if (i * prime[j] > 1000) break; 
            sf[i * prime[j]] = false;      
            if (i % prime[j] == 0) break;   
        }
    }
}
int l, r;
int ans1 = 0; int ans2 = 0;
vector<int>g[100];
void dfs(int x,int sum,int f) {
    if (sum < l) {
        if (f == 1) ans1++;
    }
    else return;
    for (int i = 0; i < g[x].size(); i++) {
        int to = g[x][i];
        if (to == 1)  dfs(to, sum * 10 + to, 1);
        else dfs(to, sum * 10 + to, f);
    }
}
void dfs2(int x, int sum,int f) {
    if (sum <= r) {
        if (f == 1) ans2++;
    }
    else return;
    for (int i = 0; i < g[x].size(); i++) {
        int to = g[x][i];
        if (to == 1)  dfs2(to, sum * 10 + to, 1);
        else dfs2(to, sum * 10 + to, f);
    }
}
void solve() {     
    for (int i = 0; i <= 9; i++) {
        for (int j = 0; j <= 9; j++) {
            if (sf[i + j])g[i].push_back(j);
        }
    }
    cin >> l >> r;
    for (int i = 1; i <= 9; i++) {
        if (i == 1) {
            dfs(i, i, 1);
            dfs2(i, i, 1);
        }
        else {
            dfs(i, i, 0);
            dfs2(i, i, 0);
        }
    }
    cout << ans2 - ans1 << endl;
}
signed main() {
    int t; t = 1;
    sushu();
    while (t--) {
        solve();
    }
    return 0;
}


E:复苏小孩

题意 | 简单

  • 给一串长度为 n n n的字符串,字符串里面的字符仅包含 ‘1’,‘2’,‘3’,分别表示使用鬼眼,鬼影,鬼手的能力。每使用其中一个鬼的能力,这个鬼就会吸收其他两个鬼各一半的能力,且假设这三种鬼的能力值为1,按照这个字符串顺序使用对应鬼的能力后,将三种鬼的力量值%998244353代入

  • m m m次操作,每行三个整数
    1 x y : 表示修改字符串的第x位修改成数字y
    2 x y : 表示查询 l,r 这段字符串

  • 0 ≤ \leq n , m n,m nm ≤ \leq 1 0 5 10^{5} 105

思路 | 线段树

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
牛客 a卷2022年第四季度的华为题目中,要求考生设计一种高效的数据结构,能够支持以下几种操作: 1. 添加一个元素 2. 删除一个元素 3. 查找是否存在某个元素 4. 返回元素的总数 该数据结构要求满足空间复杂度较小、时间复杂度较低、能够快速地进行查找和修改等多种操作。 想要编写这样一种数据结构,我们可以参考许多已有的经典算法与数据结构,如二叉树、哈希表、红黑树等,通过综合利用它们的优点来实现这个问题的解决。 例如,我们可以通过哈希表来存储所有元素的值,并在每个哈希链表的元素中再使用红黑树来进行排序与查找。这样,我们既能够轻松地进行元素的添加和删除操作,也能够在查找较大数据范围和数量时保持较高的速度与效率。同时,由于使用了多个数据结构来协同完成这个问题,我们也能够在空间复杂度上适度地进行优化。 当然,在具体设计这个数据结构的过程中,我们还需要考虑一些实践中的细节问题,例如如何避免哈希冲突、如何处理数据丢失与被删除元素所占用的空间等问题,这都需要相应的算法与流程来进行处理。 总体来看,设计这种支持多种操作的高效数据结构,需要我们具备丰富的算法知识和编程实践能力,同时需要我们在具体处理问题时能够将多种算法和数据结构进行有效地结合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值