牛客小白月赛105 题解

A. lz的吃饭问题

print("lz" if (lambda a,b: a*b)(*map(int, input().split())) < (lambda a,b: a*b)(*map(int, input().split())) else "gzy")

B. lz的数字问题

把数字按字符串处理,找到小数点则分成整数和小数两段;没有小数点则整个字符串都赋给整数部分,小数部分为空串。得到 a1,a2,b1,b2 四部分。把 a2,b2 长度补到 6,然后比较是否有 a1=b1,a2=b2 即可。

string a, b; cin >> a >> b;
// 处理数字a
int n = a.size(); string a1, a2; // 整数、小数部分
for (int i = 0; i < n; i++)
    if (a[i] == '.')  a1 = a.substr(0, i), a2 = a.substr(i + 1, min(n - i - 1, 6));
if (a1.empty()) a1 = a;
while (a2.size() < 6) a2 += '0';
// 处理数字 b
int m = b.size(); string b1, b2;
for (int i = 0; i < m; i++)
    if (b[i] == '.')  b1 = b.substr(0, i), b2 = b.substr(i + 1, min(m - i - 1, 6));
if (b1.empty()) b1 = b;
while (b2.size() < 6) b2 += '0';
// 输出答案
cout << ((a1 == b1 && a2 == b2) ? "YES\n""NO\n");

C. lz的蛋挞问题

注意到对于一个位于第一行的白色格子,只有 4 种情况下,把它变黑可以增加连通块数目:

  • 右侧、下方是白色,右下角是黑色;
  • 左侧、下方是白色,左下角是黑色;
  • 左右两边是白色,下方是黑色;
  • 左右下都是黑色。

对于第二行的格子,把“下方“改成上方即可,用二维数组搭配 i^1 切换上下可以统一。对于边缘的格子,可以在两头各加上一列黑色格子,方便处理边界情况。

for (int i = 0; i <= 1; i++) {
    scanf("%s", s[i] + 1);
    s[i][0] = s[i][n + 1] = 'x';
}
int ans = 0;
for (int i = 0; i <= 1; i++) {
    for (int j = 1; j <= n; j++) {
        if (s[i][j] == 'x') continue;
        if (s[i][j - 1] == '.' && s[i][j + 1] == '.' && s[i ^ 1][j] == 'x') ans++
        else if (s[i][j + 1] == '.' && s[i ^ 1][j] == '.' && s[i ^ 1][j + 1] == 'x') ans++;
        else if (s[i][j - 1] == '.' && s[i ^ 1][j] == '.' && s[i ^ 1][j - 1] == 'x') ans++;
        else if (s[i][j - 1] == 'x' && s[i][j + 1] == 'x' && s[i ^ 1][j] == 'x') ans++;
    }
}
printf("%d\n", ans);

D. lz的染色问题

对于 m 个询问,用并查集维护哪些花颜色要求相同。把要求同种颜色的花取出来,求一个众数,然后剩下的花颜色改成众数。可以 O(n+m),但带 log 也能过。

int count(vector<int>& v) { // 求众数个数
    sort(v.begin(), v.end(), [&](int i, int j) {  return c[i] < c[j]; }); // 排序,同种颜色的变成连续段
    int mxcnt = 1, cnt = 1;
    for (int i = 1; i < v.size(); i++)
        if (c[v[i]] == c[v[i - 1]]) cnt += 1;
        else mxcnt = max(mxcnt, cnt), cnt = 1;
    return max(mxcnt, cnt); // 注意处理最后一段
}
int main() {
    int n, m, ans = 0; cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> c[i], pa[i] = i;
    while (m--) {
        int x, y; cin >> x >> y;
        int px = find(x), py = find(y);
        if (px != py)  pa[px] = py;
    }
    map<int, vector<int>> mp;
    for (int i = 1; i <= n; i++) mp[find(i)].push_back(i); // 要求同种颜色的放在一起
    for (auto& [i, v] : mp)  ans += v.size() - count(v); // 都变成众数最优
    cout << ans << '\n';
}

E. lz的括号问题

一个括号序列可以分成几个合法的括号序列,比如 ((()))(()) 可以分成 ((()))(())。自己所在的序列之外的其它括号,显然都可以在自己前面匹配掉;而自己所在的序列中,这个括号之间的括号都可以在它之前匹配掉。把这两部分加起来就是该括号的答案。

更简单的做法是在弹栈之后看看栈里还有 x 对括号,这些括号没法在自己之前匹配上,能匹配上的就是 nx 对。

for (int i = 1; i <= n * 2; i++)
    if (s[i] == '(') st.push(i);
    else if (st.empty()) return puts("-1"), 0;
    else cnt[st.top()] = st.size(), st.pop();
if (!st.empty()) return puts("-1"), 0;
for (int i = 1; i <= n * 2; i++)
    if (s[i] != ')') printf("%d ", n - cnt[i]);

F. lz的序列问题

线段树,考虑如何合并这个前缀积和 sum,发现可以左区间 sum + 右区间 sum× 左区间区间积,而这两个属性都是支持区间赋值的——区间积直接快速幂,sum 可以用等比数列求和做。注意取模即可。

using Mod = ModInt<LL, 1000000007>; // 用了模数类
const int N = 1e5 + 10;
int n, q, a[N];
struct segtree {
    int l, r;
    Mod sum, prod, tag;
} t[N << 2];
#define ls p << 1
#define rs p << 1 | 1
#define mid ((t[p].l + t[p].r) >> 1)

inline Mod power(Mod a, int n); // 快速幂(略)
inline void refresh(int p) {
    t[p].prod = t[ls].prod * t[rs].prod;
    t[p].sum = (t[ls].sum + t[ls].prod * t[rs].sum);
}
void build(int p, int l, int r)inline void pushup(int p, Mod v) {
    t[p].tag = v;
    int len = t[p].r - t[p].l + 1;
    t[p].prod = power(v, len);
    t[p].sum = (v == 1) ? len : (power(v, len + 1) - v) / (v - 1); // 注意公比q=1时不能用公式(除0)
}
inline void pushdown(int p) {
    if (t[p].tag == 0) return;
    pushup(ls, t[p].tag);
    pushup(rs, t[p].tag);
    t[p].tag = 0;
}
void fill(int p, int l, int r, Mod v) {
    if (l <= t[p].l && t[p].r <= r) return pushup(p, v), void(0);
    pushdown(p);
    if (l <= mid) fill(ls, l, r, v);
    if (r > mid) fill(rs, l, r, v);
    refresh(p);
}
Mod get_prod(int p, int l, int r) {
    if (l <= t[p].l && t[p].r <= r) return t[p].prod;
    pushdown(p);
    Mod res = 1;
    if (l <= mid) res = res * get_prod(ls, l, r);
    if (r > mid) res = res * get_prod(rs, l, r);
    return res;
}
Mod get_sum(int p, int l, int r) {
    if (l <= t[p].l && t[p].r <= r) return t[p].sum;
    pushdown(p);
    if (l > mid) return get_sum(rs, l, r); // 注意不要写反ls,rs
    if (r <= mid) return get_sum(ls, l, r);
    return (get_sum(ls, l, r) + get_prod(ls, l, r) * get_sum(rs, l, r));
}
int main() {
    cin >> n >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    build(1, 1, n);
    while (q--) {
        int op, l, r; Mod x;
        cin >> op;
        if (op == 1) {
            cin >> l >> r >> x;
            fill(1, l, r, x);
        } else if (op == 2) {
            cin >> l >> r;
            cout << get_sum(1, l, r) << endl;
        }
    }
}
posted @   XYukari  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示