Codeforces Round 1037 (Div. 3)


A. Only One Digit

题意:求和\(x\)有至少一个相同数字且最小的数。

\(x\)数位中最小的数。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int x;
	std::cin >> x;
	int ans = 9;
	while (x) {
		ans = std::min(ans, x % 10);
		x /= 10;
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

B. No Casino in the Mountains

题意:一个\(01\)数组,所有连续\(0\)子数组拿\(k\)个空一个,如此循环直到拿不了。求总共放几个长度为\(k\)的子数组。

模拟。
对于一个长度为\(len\)的全\(0\)子数组,贡献为\(\lfloor \frac{len}{k+1} \rfloor + [len \% (k + 1) = k]\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, k;
	std::cin >> n >> k;
	std::vector<int> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	int ans = 0;
	for (int i = 0; i < n; ++ i) {
		if (a[i] == 0) {
			int j = i;
			while (j + 1 < n && a[j + 1] == 0) {
				++ j;
			}

			int len = j - i + 1;
			ans += len / (k + 1) + (len % (k + 1) == k);
			i = j;
		}
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

C. I Will Definitely Make It

题意:一些高度为\(h_i\)的柱子。一开始在第\(k\)个柱子上。从一个柱子到另一个柱子花费时间是高度差,且到达之前高度都不变。一开始水位高度为\(1\)。每秒上升\(1\)。求能不能到最高的位置。

只和高度有关,直接排序。然后相邻两个爬就行了。因为发现\(r - l = r - k + k - l\)。所以一直跳距离最近的位置是最优的,模拟判断就行了。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, k;
	std::cin >> n >> k;
	-- k;
	std::vector<int> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	int h = a[k];
	std::ranges::sort(a);
	for (int i = 0, j = 0; i < n; ++ i) {
		if (a[i] <= h) {
			continue;
		}

		if (a[i] - h + j > h) {
			std::cout << "NO\n";
			return;
		}

		j += a[i] - h;
		h = a[i];
	}
	std::cout << "YES\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

D. This Is the Last Time

题意:一开始有\(k\)元,有\(n\)个赌场,如果\(l_i \leq k \leq r_i\)就可以把\(k\)变成\(w_i\), \(w_i \in [l_i, r_i]\)。求最多有多少钱。

不可能有一步减少钱的情况。因为如果需要变成一个\(k' < k\),如果有\(l_i \leq k' \leq r_i\)\(w_i > k\),那么\(l_i \leq k \leq r_i\)。因为\(k < w_i \leq r_i\)。所以按\(w_i\)排序,循环跑一遍。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, k;
	std::cin >> n >> k;
	std::vector<std::tuple<int, int, int>> a(n);
	for (int i = 0; i < n; ++ i) {
		int l, r, w;
		std::cin >> l >> r >> w;
		a[i] = {w, l, r};
	}

	std::ranges::sort(a);
	for (auto & [w, l, r] : a) {
		if (l <= k && k <= r) {
			k = std::max(k, w);
		}
	}
	std::cout << k << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

E. G-C-D, Unlucky!

题意:\(p\)\(a\)的前缀\(gcd\)数组,\(s\)\(a\)的后缀\(gcd\)数组。求有没有一个合法的\(a\)

直接猜的。
就是判断是不是所有的\(i\)都有\(gcd(p_i, s_{i+1}) = s_1\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> a(n), b(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	for (int i = 0; i < n; ++ i) {
		std::cin >> b[i];
	}

	for (int i = 0; i < n; ++ i) {
		if (i + 1 < n && a[i] % a[i + 1]) {
			std::cout << "NO\n";
			return;
		}

		if (i && b[i] % b[i - 1]) {
			std::cout << "NO\n";
			return;
		}
	}

	if (b[0] != a.back()) {
		std::cout << "NO\n";
		return;
	}

	for (int i = 0; i + 1 < n; ++ i) {
		if (std::gcd(a[i], b[i + 1]) != b[0]) {
			std::cout << "NO\n";
			return;
		}
	}
	
	std::cout << "YES\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

F. 1-1-1, Free Tree!

题意:一棵树,每个点有颜色,每条边有权值。如果一条边两个点颜色相同,代价为\(0\),否则代价为权值。每次修改一个点的颜色,求总代价。

upd:根号分治被hack了。
正确做法应该是\(dfs\)一遍树,然后每个点用\(map\)存子节点不同颜色的边权和。
每次改变一个点就和父节点单独讨论一下,改一下父节点的\(map\),然后跟子节点讨论直接用\(map\)加减。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, q;
	std::cin >> n >> q;
	std::vector<int> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	std::vector<std::vector<std::pair<int, int>>> adj(n);
	for (int i = 1; i < n; ++ i) {
		int u, v, w;
		std::cin >> u >> v >> w;
		-- u, -- v;
		adj[u].emplace_back(v, w);
		adj[v].emplace_back(u, w);
	}

	std::vector<std::map<int, i64>> mp(n);
	i64 ans = 0;
	std::vector<int> fa(n, -1), val(n);
	auto dfs = [&](auto & self, int u) -> void {
		for (auto & [v, w] : adj[u]) {
			if (v == fa[u]) {
				continue;
			}

			fa[v] = u;
			val[v] = w;
			mp[u][a[v]] += w;
			self(self, v);
			if (a[u] != a[v]) {
				ans += w;
			}
		}
	};

	dfs(dfs, 0);

	while (q -- ) {
		int u, x;
		std::cin >> u >> x;
		-- u;
		if (fa[u] != -1) {
			if (a[u] == a[fa[u]]) {
				ans += val[u];
			}

			if (x == a[fa[u]]) {
				ans -= val[u];
			}

			mp[fa[u]][a[u]] -= val[u];
			mp[fa[u]][x] += val[u];
		}

		if (mp[u].count(a[u])) {
			ans += mp[u][a[u]];
		}

		if (mp[u].count(x)) {
			ans -= mp[u][x];
		}

		a[u] = x;
		std::cout << ans << "\n";
	}
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

G. Big Wins!

题意:求一个数组的一个子区间的中位数减最小值的最大值。

一个\(trick\)是,如果我们求\(med\)是不是大于等于\(m\),可以把数组里小于\(m\)的位置设为\(-1\),否则设为\(1\)。那么一个子区间\(med\)大于等于\(m\),则区间和大于等于\(0\)
那么我们可以用维护区间最大最小值的线段树维护前缀和的最值,枚举中位数,每次操作完后把等于当前枚举的中位数的位置的后缀都减去\(-2\),因为是从\(1\)变为了\(-1\),减少了\(2\),然后因为是维护的前缀和,所以对后面的位置都要减\(2\)
那么固定了中位数,怎么求最小值?我们可以把\((a_i, i)\)排序,那么就可以从小的数遍历大的数,我们用一个单调栈预处理每个位置作为最小值的左右区间\([L_i, R_i]\),如果\([i, R_i]\)的最大值减\([L_i - 1, i - 1]\)的最小值小于\(0\)则以这个位置为最小值不行。因为中位数也是从小到大枚举,那么当前位置对于这个中位数不行,对于更大的中位数也不行,则可以用一个指针维护,做到线性枚举。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

template <class Info, class Tag>
struct LazySegmentTree {
    struct Node {
        int l, r;
        Info info;
        Tag tag;
    };

    std::vector<Node> tr;
    LazySegmentTree() {}
    LazySegmentTree(int n) {
        init(n);
    }

    LazySegmentTree(const std::vector<int> & a) {
        init(a);
    }

    void init(int n) {
        tr.assign(n << 2, {});
        build(0, n - 1);
    }

    void init(const std::vector<int> & a) {
        int n = a.size();
        tr.assign(n << 2, {});
        auto build = [&](auto & self, int l, int r, int u = 1) -> void {
            tr[u] = {l, r, {}};
            if (l == r) {
                tr[u].info.max = tr[u].info.min = a[l];
                return;
            }

            int mid = l + r >> 1;
            self(self, l, mid, u << 1); self(self, mid + 1, r, u << 1 | 1);
            pushup(u);
        };

        build(build, 0, n - 1);
    }

    void pushdown(Node & u, const Tag & tag) {
        u.info = u.info + tag;
        u.tag = u.tag + tag;
    }

    void pushdown(int u) {
        if (tr[u].tag.exist()) {
            pushdown(tr[u << 1], tr[u].tag);
            pushdown(tr[u << 1 | 1], tr[u].tag);
            tr[u].tag.clear();
        }
    }

    void pushup(int u) {
        tr[u].info = tr[u << 1].info + tr[u << 1 | 1].info;
    }

    void build(int l, int r, int u = 1) {
        tr[u] = {l, r, {}};
        if (l == r) {

            return;
        }

        int mid = l + r >> 1;
        build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
        pushup(u);
    }

    void modify(int l, int r, const Tag & tag, int u = 1) {
        if (l <= tr[u].l && tr[u].r <= r) {
            pushdown(tr[u], tag);
            return;
        }

        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) {
            modify(l, r, tag, u << 1);
        }

        if (r > mid) {
            modify(l, r, tag, u << 1 | 1);
        }

        pushup(u);
    }

    Info query(int l, int r, int u = 1) {
        if (l <= tr[u].l && tr[u].r <= r) {
            return tr[u].info;
        }

        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (r <= mid) {
            return query(l, r, u << 1);
        } else if (l > mid) {
            return query(l, r, u << 1 | 1);
        }

        return query(l, r, u << 1) + query(l, r, u << 1 | 1);
    }
};

struct Info {
    int max, min;
};

struct Tag {
    int add;
    bool exist() {
        return add != 0;
    }

    void clear() {
        add = 0;
    }
};

Info operator + (const Info & a, const Info & b) {
    Info res{};
    res.max = std::max(a.max, b.max);
    res.min = std::min(a.min, b.min);
    return res;
}

Info operator + (const Info & a, const Tag & b) {
    Info res{};
    res.max = a.max + b.add;
    res.min = a.min + b.add;
    return res;
}

Tag operator + (const Tag & a, const Tag & b) {
    Tag res{};
    res.add = a.add + b.add;
    return res;
}

void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n + 1);
    std::vector<std::pair<int, int>> b;
    std::vector<std::vector<int>> pos(n + 1);
    for (int i = 1; i <= n; ++ i) {
        std::cin >> a[i];
        pos[a[i]].push_back(i);
        b.emplace_back(a[i], i);
    }

    a.push_back(0);
    std::ranges::sort(b);
    std::stack<int> stk;
    stk.push(0);
    std::vector<int> L(n + 2), R(n + 2);
    for (int i = 1; i <= n + 1; ++ i) {
        while (a[stk.top()] > a[i]) {
            R[stk.top()] = i - 1;
            stk.pop();
        }

        L[i] = stk.top() + 1;
        stk.push(i);
    }

    std::vector<int> info(n + 1, 1);
    info[0] = 0;
    for (int i = 1; i <= n; ++ i) {
        info[i] += info[i - 1];
    }
    LazySegmentTree<Info, Tag> tr(info);

    auto check = [&](int p) -> bool {
        int max = tr.query(p, R[p]).max;
        int min = tr.query(L[p] - 1, p - 1).min;
        return max - min >= 0;
    };

    int ans = 0;
    for (int med = 1, p = 0; med <= n; ++ med) {
        while (p < n && !check(b[p].second)) {
            ++ p;
        }

        if (p < n) {
            ans = std::max(ans, med - a[b[p].second]);
        }

        for (auto & i : pos[med]) {
            tr.modify(i, n, Tag{-2});
        }
    }
    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    int t = 1;
    std::cin >> t;
    while (t -- ) {
        solve();
    }
    return 0;
}
posted @ 2025-07-18 00:58  maburb  阅读(1056)  评论(1)    收藏  举报