AtCoder Beginner Contest 417


A - A Substring

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

using i64 = long long;

void solve() {
	int n, a, b;
	std::cin >> n >> a >> b;
	std::string s;
	std::cin >> s;
	std::cout << s.substr(a, n - a - b) << "\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 - Search and Delete

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

using i64 = long long;

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

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

	std::map<int, int> cnt;
	for (auto & x : b) {
		++ cnt[x];
	}

	for (int i = 0; i < n; ++ i) {
		if (cnt[a[i]] == 0) {
			std::cout << a[i] << " ";
		} else {
			-- cnt[a[i]];
		}
	}
	std::cout << "\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 - Distance Indicators

题意:给你一个数组\(a\),求有多少\(i, j\)满足\(i < j\)\(j - i = a_i + a_j\)

式子可以变为:\(j - a_j = a_i + i\)
那么用\(map\)记录前缀\(a_i + i\)的个数就行。

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

using i64 = long long;

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

	std::map<int, int> cnt;
	i64 ans = 0;
	for (int i = 0; i < n; ++ i) {
		ans += cnt[i - a[i]];
		++ cnt[a[i] + i];
	}
	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;
}

D - Takahashi's Expectation

题意:有\(n\)个三元组\((p_i, a_i, b_i)\)。开始有一个\(x\),然后从前往后遍历这些三元组,如果\(p_i \geq x\)\(x\)变为\(x+a_i\),否则\(x\)变为\(\max(0, x - b_i)\)\(q\)次询问,每次给定\(x\),求其最后变成的数。\(p_i, a_i, b_i \leq 500\)

观察到三元组的范围都很小,如果\(x \leq 500\)我们进行模拟,如果\(x > 500\),那么它要一直减\(b_i\)直到小于等于\(500\),可以二分找到这个位置,然后让这个询问从这个位置开始。
也就是我们可以离线查询,每个\(x\)有一个起点和在这个起点的值,于是可以从前往后遍历三元组,每次把以这个位置为起点的询问加进来操作就行。可以用并查集维护每个值对应的查询编号,当两个查询在同一个位置的值一样的时候,我们合并它们,最后每个询问找到自己的祖先的值就是答案。

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

using i64 = long long;

struct DSU {
	std::vector<int> fa, cnt;
	DSU();
	DSU(int n) {
		init(n);
	}

	void init(int n) {
		fa.assign(n + 1, 0);
		cnt.assign(n + 1, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	bool merge(int x, int y) {
		int u = find(x), v = find(y);
		if (u == v) {
			return false;
		}

		fa[v] = u;
		cnt[u] += cnt[v];
		return true;
	}

	bool same(int u, int v) {
		return find(u) == find(v);
	}

	int size(int u) {
		return cnt[find(u)];
	}
};

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

	std::vector<int> sum(n);
	sum[0] = b[0];
	for (int i = 1; i < n; ++ i) {
		sum[i] = sum[i - 1] + b[i];
	}

	int q;
	std::cin >> q;
	std::vector<std::vector<std::pair<int, int>>> add(n);
	std::vector<int> ans(q);
	for (int i = 0; i < q; ++ i) {
		int x;
		std::cin >> x;
		if (x <= 500) {
			add[0].emplace_back(x, i);
		} else {
			if (x - 500 > sum[n - 1]) {
				ans[i] = x - sum[n - 1];
			} else {
				int p = std::ranges::lower_bound(sum, x - 500) - sum.begin();
				add[p].emplace_back(x - (p > 0 ? sum[p - 1] : 0), i);
			}
		}	
	}

	std::array<int, 1001> f{};
	f.fill(-1);
	DSU dsu(q);
	for (int i = 0; i < n; ++ i) {
		for (auto & [x, j] : add[i]) {
			if (f[x] != -1) {
				dsu.merge(f[x], j);
			} else {
				f[x] = j;
			}
		}

		std::array<int, 1001> g{};
		g.fill(-1);
		for (int x = 0; x <= 1000; ++ x) {
			if (f[x] != -1) {
				int y = p[i] >= x ? x + a[i] : std::max(0, x - b[i]);
				if (g[y] != -1) {
					dsu.merge(g[y], f[x]);
				} else {
					g[y] = f[x];
				}
			}
		}

		f = g;
	}

	for (int i = 0; i <= 1000; ++ i) {
		if (f[i] != -1) {
			ans[f[i]] = i;
		}
	}

	for (int i = 0; i < q; ++ i) {
		ans[i] = ans[dsu.find(i)];
	}

	for (int i = 0; i < q; ++ i) {
		std::cout << ans[i] << "\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 - A Path in A Dictionary

题意:给你一个图,求从\(x\)\(y\)的路径中进过点的编号的序列的字典序最小的路径。

每个点都优先走编号最小的邻点。\(dfs\)一遍就行。
因为想要字典序最小肯定前面的位置选小的数更好,那么优先走小的点,只有这个点不通的情况才走其它点中最小点,因为能保证前面的数尽可能小,所以这样是字典序最小的。

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

using i64 = long long;

void solve() {
	int n, m, x, y;
	std::cin >> n >> m >> x >> y;
	-- x, -- y;
	std::vector<std::vector<int>> adj(n);
	for (int i = 0; i < m; ++ i) {
		int u, v;
		std::cin >> u >> v;
		-- u, -- v;
		adj[u].push_back(v);
		adj[v].push_back(u);
	}

	for (int i = 0; i < n; ++ i) {
		std::ranges::sort(adj[i]);
	}

	std::vector<int> pre(n, -1);
	auto dfs = [&](auto & self, int u) -> void {
		for (auto & v : adj[u]) {
			if (pre[v] == -1) {
				pre[v] = u;
				self(self, v);
			}
		}
	};

	pre[x] = x;
	dfs(dfs, x);

	std::vector<int> ans;
	while (y != x) {
		ans.push_back(y);
		y = pre[y];
	}
	ans.push_back(x);
	std::ranges::reverse(ans);
	for (auto & x : ans) {
		std::cout << x + 1 << " \n"[x == ans.back()];
	}
}

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 - Random Gathering

题意:一个数组初始为\(a_i\),有\(m\)个操作,每次把\([l_i, r_i]\)之间的和记为\(s\),然后把\([l_i, r_i\)的数都变成\(0\)。最后把\(s\)随机赋值给\([l_i, r_i]\)的一个数。最后求每个位置的期望。

如果\(p_i\)表示当前\(i\)的期望,那么对于一个操作\([l, r]\),和的期望就是期望的和,也就是\(sum = \sum_{i=l}^{r} p_i\),那么每个位置的期望就是\(\frac{sum}{r-l+1}\)
用可以维护区间赋值和区间求和的线段树就行。

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

using i64 = long long;

template<class T>
constexpr T power(T a, i64 b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}

constexpr i64 mul(i64 a, i64 b, i64 p) {
    i64 res = a * b - i64(1.L * a * b / p) * p;
    res %= p;
    if (res < 0) {
        res += p;
    }
    return res;
}
template<i64 P>
struct MLong {
    i64 x;
    constexpr MLong() : x{} {}
    constexpr MLong(i64 x) : x{norm(x % getMod())} {}
    
    static i64 Mod;
    constexpr static i64 getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(i64 Mod_) {
        Mod = Mod_;
    }
    constexpr i64 norm(i64 x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr i64 val() const {
        return x;
    }
    explicit constexpr operator i64() const {
        return x;
    }
    constexpr MLong operator-() const {
        MLong res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MLong inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MLong &operator*=(MLong rhs) & {
        x = mul(x, rhs.x, getMod());
        return *this;
    }
    constexpr MLong &operator+=(MLong rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MLong &operator-=(MLong rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MLong &operator/=(MLong rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MLong operator*(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MLong operator+(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MLong operator-(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MLong operator/(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MLong &a) {
        i64 v;
        is >> v;
        a = MLong(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MLong &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MLong lhs, MLong rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MLong lhs, MLong rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
i64 MLong<0LL>::Mod = i64(1E18) + 9;

template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(i64 x) : x{norm(x % getMod())} {}
    
    static int Mod;
    constexpr static int getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr int norm(int x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MInt &operator*=(MInt rhs) & {
        x = 1LL * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
        i64 v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
int MInt<0>::Mod = 998244353;

template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

constexpr int P = 998244353;
using Z = MInt<P>;

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);
	}

	void init(int n) {
		tr.assign(n << 2, {});
		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 {
	Z sum, len = 1;
};

struct Tag {
	Z set;
	bool exist() {
		return set != 0;
	}

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

Info operator + (const Info & a, const Info & b) {
	Info res{};
	res.sum = a.sum + b.sum;
	res.len = a.len + b.len;
	return res;
}

Info operator + (const Info & a, const Tag & b) {
	Info res{};
	res.sum = b.set * a.len;
	res.len = a.len;
	return res;
}

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

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

	LazySegmentTree<Info, Tag> tr(n);
	for (int i = 0; i < n; ++ i) {
		tr.modify(i, i, Tag{(Z)a[i]});
	}

	for (int i = 0; i < m; ++ i) {
		int l, r;
		std::cin >> l >> r;
		-- l, -- r;
		auto [sum, len] = tr.query(l, r);
		tr.modify(l, r, Tag{sum / len});
	}

	for (int i = 0; i < n; ++ i) {
		std::cout << tr.query(i, i).sum << " \n"[i == n - 1];
	}
}

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-08-02 21:40  maburb  阅读(137)  评论(0)    收藏  举报