牛客小白月赛86 A - F

水盐平衡

  • 思维
  • 判断一下浓度大小,再选择加水还是加盐。
signed main() {

    int T = 1;
    T = read();
    while (T--) {
        vector<int> a(5);
        for (int i = 1; i <= 4; ++i) a[i] = read();
        int t1 = a[1] * a[4], t2 = a[2] * a[3];
        t1 > t2? puts("S"): puts("Y");
    }
    return 0;
}

水平考试

  • 思维
  • 无论多选还是单选,有错的选项 0 0 0 分,没选全满分(小灰灰会填满)。
signed main() {

    int T = 1;
    T = read();
    while (T--) {
        string s1, s2; cin >> s1 >> s2;
        bool f = 1;
        for (auto it: s1) {
            if (s2.find(it) == -1) {
                f = 0;
                break;
            }
        }
        if (s2.size() > 1) f? puts("10"): puts("0");
        else f? puts("10"): puts("0");
    }
    return 0;
}

数组段数

  • 前缀和
  • p r e f i pref_i prefi 表示从 1 1 1 i i i 最少划分多少段。
  • 注意:如果 a i = = a l − 1 a_i==a_{l-1} ai==al1 你得保留从 a l a_l al 开始的那段。
signed main() {

    int T = 1;
//    T = read();
    while (T--) {
        int n = read(), m = read();
        vector<int> a(n + 1), pref(n + 1);
        for (int i = 1; i <= n; ++i) a[i] = read();
        for (int i = 1; i <= n; ++i) {
            if (a[i] ^ a[i - 1]) pref[i] = 1;
            pref[i] += pref[i - 1];
        }
        while (m--) {
            int l = read(), r = read();
            writeln(pref[r] - pref[l - 1] + (a[l - 1] == a[l]));
        }
    }
    return 0;
}

剪纸游戏

  • d f s dfs dfs
  • 题目说明了剪下来的图案不会联通,那么跑 d f s dfs dfs 的时候就记录一下面积,同时筛选出最小的行,列和最大的行,列。如果是一个矩形那么 S = ( l i n e m a x − l i n e m i n ) ⋅ ( c o l u m n m a x − c o l u m n m i n ) S = (line_{max}-line_{min})\cdot(column_{max}-column_{min}) S=(linemaxlinemin)(columnmaxcolumnmin) ,判断并记录答案即可。
string mp[SN];
int n, m;
int d[4][2] = {0, -1, 0, 1, -1, 0, 1, 0};
bool vis[SN][SN];
tuple<int, int, int, int, int> dfs(int x, int y) {
    int x1 = x, y1 = y, x2 = x, y2 = y, sum1 = 1;
    for (int i = 0; i < 4; ++i) {
        int xx = x + d[i][0], yy = y + d[i][1];
        if (xx < 0 || yy < 0 || xx >= n || yy >= m || vis[xx][yy] || mp[xx][yy] == '*') continue;
        vis[xx][yy] = 1;
        auto [xs1, ys1, xs2, ys2, sum] = dfs(xx, yy);
        x1 = min(x1, xs1), y1 = min(y1, ys1);
        x2 = max(x2, xs2), y2 = max(y2, ys2);
        sum1 += sum;
    }
    return {x1, y1, x2, y2, sum1};
}
signed main() {

    int T = 1;
//    T = read();
    while (T--) {
        n = read(), m = read();
        for (int i = 0; i < n; ++i) cin >> mp[i];
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < mp[i].size(); ++j) {
                if (mp[i][j] ^ '*' && !vis[i][j]) {
                    vis[i][j] = 1;
                    auto [x1, y1, x2, y2, sum] = dfs(i, j);
                    if ((x2 - x1 + 1) * (y2 - y1 + 1) == sum) ++ans;
                }
            }
        }
        write(ans);
    }
    return 0;
}

可口蛋糕

  • 前缀和 + 枚举 + 双指针 O ( n ) O(n) O(n) o r or or 线段树 + 二分 O ( n l o g n ) O(nlogn) O(nlogn)
  • 从左往右枚举右端点,在保证 W W W 的情况下,你可以得出区间 [ 1    ,    j ] [1\;,\;j] [1,j] ,在这个区间选择一个左端点然后减去 1 1 1 到左端点的前缀和,因为是减去所以左端点的选定是区间 [ 1    ,    j ] [1\;,\;j] [1,j] 的最小值的索引。
  • 双指针左端点就保证 W W W 的情况一直往右移动选出最小值就好,
  • 注意:更新答案一定是满足 W W W 的情况下才能更新。

线段树 c o d e code code

vector<int> w(N), d(N), prefd(N), prefw(N);
struct p {
    int l, r, Min;
}tr[N << 2];
void pushup(int i) { tr[i].Min = min (tr[ls].Min, tr[rs].Min); }
void build(int i, int l, int r) {
    tr[i] = {l, r, (int)1e18};
    if (l == r) {
        tr[i].Min = prefd[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build(ls, l, mid), build(rs, mid + 1, r);
    pushup(i);
}
int query(int i, int l, int r) {
    if (tr[i].l >= l && tr[i].r <= r) return tr[i].Min;
    int res = 1e18;
    if (tr[ls].r >= l) res = min(res, query(ls, l, r));
    if (tr[rs].l <= r) res = min(res, query(rs, l, r));
    return res;
}
signed main() {

    int T = 1;
//    T = read();
    while (T--) {
        int n = read(), W = read();
        for (int i = 1; i <= n; ++i) {
            prefw[i] = w[i] = read();
            prefw[i] += prefw[i - 1];
        }
        for (int i = 1; i <= n; ++i) {
            prefd[i] = d[i] = read();
            prefd[i] += prefd[i - 1];
        }
        build(1, 1, n);
        int res = 0, ans = -1e18, ww = 0;
        for (int i = 1; i <= n; ++i) {
            ww += w[i], res += d[i];
            if (ww >= W) {
                int pos = upper_bound(prefw.begin() + 1, prefw.begin() + i + 1, ww - W) - prefw.begin();
                if (!--pos) continue;
                ans = max({ans, res - query(1, 1, pos), res});
            }
        }
        write(ans);
    }
    return 0;
}

双指针 c o d e code code

signed main() {
 
    int T = 1;
//    T = read();
    while (T--) {
		vector<int> w(N), d(N), prefd(N), prefw(N);
        int n = read(), W = read();
        for (int i = 1; i <= n; ++i) {
            prefw[i] = w[i] = read();
            prefw[i] += prefw[i - 1];
        }
        for (int i = 1; i <= n; ++i) {
            prefd[i] = d[i] = read();
            prefd[i] += prefd[i - 1];
        }
        int res = 0, ans = -1e18, ww = 0, l = 0, Min = 1e18;
        for (int i = 1; i <= n; ++i) {
            ww += w[i], res += d[i];
            while (ww - W >= prefw[l]) Min = min(Min, prefd[l++]);
            ans = max({ans, res - Min});
        }
        write(ans);
    }
    return 0;
}

喜欢序列

  • s e t set set + 树状数组 o r or or 线段树
  • 预处理断点, s e t set set 存断点下标。
  • 考虑加上 w w w l , r l,r l,r 处的关联情况。
    • l l l 与前一个断点相邻, r r r 不为断点。
    • l l l 与前一个断点相邻, r r r 为断点。
    • l l l 与前一个断点不相邻, r r r 不为断点。
    • l l l 与前一个断点不相邻, r r r 为断点。
  • 在断点处的情况考虑更新后两个区间是否能合并即可。
  • 不在断点处更新后则从端点处断开即可。
  • 注意:断点下标可能为 0    o r    n 0\;or\;n 0orn 此时不用断开。

树状数组 c o d e code code

vector<int> a(N), tr(N);
signed main() {
    auto add = [] (int x, int n, int v) {
        for (int i = x; i <= n; i += lowbit(i)) tr[i] += v;
    };
    auto query = [&] (int x, int n) {
        int ans = 0;
        for (int i = x; i; i -= lowbit(i)) ans += tr[i];
        return ans;
    };
    int T = 1;
//    T = read();
    while (T--) {
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            a[i] = read();
            add(i, n, a[i] - a[i - 1]);
        }
        set<int> endpos;
        for (int i = 1; i <= n; ++i) {
            if (a[i] ^ (a[i - 1] + 1)) endpos.insert(i - 1);
        }
        endpos.insert(0), endpos.insert(n);
        int s = 0, pre = 0;
        for (auto it: endpos) {
            s += (it - pre) * (it - pre);
            pre = it;
        }
        auto powt = [&] (int x) {
            return x * x;
        };
        while (m--) {
            int l = read(), r = read(), w = read();
            if (!w) {
                writeln(s);
                continue;
            }
            add(l, n, w), add(r + 1, n, -w);
            auto pos1 = endpos.lower_bound(l), pos2 = endpos.lower_bound(r);
            if (l == *prev(pos1) + 1 && r ^ *pos2) {
                if (*prev(pos1)) {
                    int v1 = query(l - 1, n), v2 = query(l, n);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*pos1 - *prev(pos1)), t2 = powt(*prev(pos1) - *prev(prev(pos1)));
                        int t3 = powt(*pos1 - *prev(prev(pos1)));
                        s = s - t1 - t2 + t3;
                        endpos.erase(l - 1);
                    }
                }
                int t1 = powt(*pos2 - *prev(pos2));
                int t2 = powt(*pos2 - r), t3 = powt(r - *prev(pos2));
                s = s - t1 + t2 + t3;
                endpos.insert(r);
            }
            else if (l == *prev(pos1) + 1 && r == *pos2) {
                if (*prev(pos1)) {
                    int v1 = query(l - 1, n), v2 = query(l, n);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*pos1 - *prev(pos1)), t2 = powt(*prev(pos1) - *prev(prev(pos1)));
                        int t3 = powt(*pos1 - *prev(prev(pos1)));
                        s = s - t1 - t2 + t3;
                        endpos.erase(l - 1);
                    }
                }
                if (r ^ n) {
                    int v1 = query(r, n), v2 = query(r + 1, n);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*next(pos2) - r), t2 = powt(r - *prev(pos2));
                        int t3 = powt(*next(pos2) - *prev(pos2));
                        s = s - t1 - t2 + t3;
                        endpos.erase(r);
                    }
                }
            }
            else if (l ^ (*prev(pos1) + 1) && r == *pos2) {
                if (r ^ n) {
                    int v1 = query(r, n), v2 = query(r + 1, n);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*next(pos2) - r), t2 = powt(r - *prev(pos2));
                        int t3 = powt(*next(pos2) - *prev(pos2));
                        s = s - t1 - t2 + t3;
                        endpos.erase(r);
                    }
                }
                int t1 = powt(*pos1 - *prev(pos1));
                int t2 = powt(*pos1 - l + 1), t3 = powt(l - 1 - *prev(pos1));
                s = s - t1 + t2 + t3;
                endpos.insert(l - 1);
            }
            else if (l ^ (*prev(pos1) + 1) && r ^ *pos2) {
                int t1 = powt(*pos1 - *prev(pos1));
                int t2 = powt(*pos1 - l + 1), t3 = powt(l - 1 - *prev(pos1));
                s = s - t1 + t2 + t3;
                endpos.insert(l - 1);
                t1 = powt(*pos2 - *prev(pos2));
                t2 = powt(*pos2 - r), t3 = powt(r - *prev(pos2));
                s = s - t1 + t2 + t3;
                endpos.insert(r);
            }
            writeln(s);
        }
    }
    return 0;
}

线段树 c o d e code code

vector<int> a(N);
struct p {
    int l, r, v, tag;
}tr[N << 2];
void build(int i, int l, int r) {
    tr[i] = {l, r, 0, 0};
    if (l == r) {
        tr[i].v = a[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build(ls, l, mid), build(rs, mid + 1, r);
}
void pushdown(int i) {
    if (tr[i].tag) {
        tr[ls].tag += tr[i].tag, tr[rs].tag += tr[i].tag;
        tr[ls].v += (tr[ls].r - tr[ls].l + 1) * tr[i].tag;
        tr[rs].v += (tr[rs].r - tr[rs].l + 1) * tr[i].tag;
        tr[i].tag = 0;
    }
}
void modify(int i, int l, int r, int k) {
    if (tr[i].l >= l && tr[i].r <= r) {
        tr[i].tag += k;
        tr[i].v += k;
        return ;
    }
    pushdown(i);
    if (tr[ls].r >= l) modify(ls, l, r, k);
    if (tr[rs].l <= r) modify(rs, l, r, k);
}
int query(int i, int pos) {
    if (tr[i].l == tr[i].r) return tr[i].v;
    pushdown(i);
    if (pos <= tr[ls].r) return query(ls, pos);
    else return query(rs, pos);
}
signed main() {
 
    int T = 1;
//    T = read();
    while (T--) {
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) a[i] = read();
        build(1, 1, n);
        set<int> endpos;
        for (int i = 1; i <= n; ++i) {
            if (a[i] ^ (a[i - 1] + 1)) endpos.insert(i - 1);
        }
        endpos.insert(0), endpos.insert(n);
        int s = 0, pre = 0;
        for (auto it: endpos) {
            s += (it - pre) * (it - pre);
            pre = it;
        }
        auto powt = [&] (int x) {
            return x * x;
        };
        for (int i = 1; i <= m; ++i) {
            int l = read(), r = read(), w = read();
            if (!w) {
                writeln(s);
                continue;
            }
            modify(1, l, r, w);
            auto pos1 = endpos.lower_bound(l), pos2 = endpos.lower_bound(r);
            if (l == *prev(pos1) + 1 && r ^ *pos2) {
                if (*prev(pos1)) {
                    int v1 = query(1, l - 1), v2 = query(1, l);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*pos1 - *prev(pos1)), t2 = powt(*prev(pos1) - *prev(prev(pos1)));
                        int t3 = powt(*pos1 - *prev(prev(pos1)));
                        s = s - t1 - t2 + t3;
                        endpos.erase(l - 1);
                    }
                }
                int t1 = powt(*pos2 - *prev(pos2));
                int t2 = powt(*pos2 - r), t3 = powt(r - *prev(pos2));
                s = s - t1 + t2 + t3;
                endpos.insert(r);
            }
            else if (l == *prev(pos1) + 1 && r == *pos2) {
                if (*prev(pos1)) {
                    int v1 = query(1, l - 1), v2 = query(1, l);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*pos1 - *prev(pos1)), t2 = powt(*prev(pos1) - *prev(prev(pos1)));
                        int t3 = powt(*pos1 - *prev(prev(pos1)));
                        s = s - t1 - t2 + t3;
                        endpos.erase(l - 1);
                    }
                }
                if (r ^ n) {
                    int v1 = query(1, r), v2 = query(1, r + 1);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*next(pos2) - r), t2 = powt(r - *prev(pos2));
                        int t3 = powt(*next(pos2) - *prev(pos2));
                        s = s - t1 - t2 + t3;
                        endpos.erase(r);
                    }
                }
            }
            else if (l ^ (*prev(pos1) + 1) && r == *pos2) {
                if (r ^ n) {
                    int v1 = query(1, r), v2 = query(1, r + 1);
                    if (v1 + 1 == v2) {
                        int t1 = powt(*next(pos2) - r), t2 = powt(r - *prev(pos2));
                        int t3 = powt(*next(pos2) - *prev(pos2));
                        s = s - t1 - t2 + t3;
                        endpos.erase(r);
                    }
                }
                int t1 = powt(*pos1 - *prev(pos1));
                int t2 = powt(*pos1 - l + 1), t3 = powt(l - 1 - *prev(pos1));
                s = s - t1 + t2 + t3;
                endpos.insert(l - 1);
            }
            else if (l ^ (*prev(pos1) + 1) && r ^ *pos2) {
                int t1 = powt(*pos1 - *prev(pos1));
                int t2 = powt(*pos1 - l + 1), t3 = powt(l - 1 - *prev(pos1));
                s = s - t1 + t2 + t3;
                endpos.insert(l - 1);
                t1 = powt(*pos2 - *prev(pos2));
                t2 = powt(*pos2 - r), t3 = powt(r - *prev(pos2));
                s = s - t1 + t2 + t3;
                endpos.insert(r);
            }
            writeln(s);
        }
    }
    return 0;
}
  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
牛客 a卷2022年第四季度的华为题目中,要求考生设计一种高效的数据结构,能够支持以下几种操作: 1. 添加一个元素 2. 删除一个元素 3. 查找是否存在某个元素 4. 返回元素的总数 该数据结构要求满足空间复杂度较小、时间复杂度较低、能够快速地进行查找和修改等多种操作。 想要编写这样一种数据结构,我们可以参考许多已有的经典算法与数据结构,如二叉树、哈希表、红黑树等,通过综合利用它们的优点来实现这个问题的解决。 例如,我们可以通过哈希表来存储所有元素的值,并在每个哈希链表的元素中再使用红黑树来进行排序与查找。这样,我们既能够轻松地进行元素的添加和删除操作,也能够在查找较大数据范围和数量时保持较高的速度与效率。同时,由于使用了多个数据结构来协同完成这个问题,我们也能够在空间复杂度上适度地进行优化。 当然,在具体设计这个数据结构的过程中,我们还需要考虑一些实践中的细节问题,例如如何避免哈希冲突、如何处理数据丢失与被删除元素所占用的空间等问题,这都需要相应的算法与流程来进行处理。 总体来看,设计这种支持多种操作的高效数据结构,需要我们具备丰富的算法知识和编程实践能力,同时需要我们在具体处理问题时能够将多种算法和数据结构进行有效地结合。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_sealy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值