VP Educational Codeforces Round 72 (Rated for Div. 2)


A. Creating a Character

题意:给你\(a, b, c\),把\(c\)分给\(a, b\),求\(a > b\)的方案数。

可以二分分给多少个给\(a\)

点击查看代码
void solve() {
    int a, b, c;
    std::cin >> a >> b >> c;
    if (a + c <= b) {
    	std::cout << 0 << "\n";
    	return;
    }
    int l = 0, r = c;
    while (l < r) {
    	int mid = l + r >> 1;
    	if (a + mid > b + c - mid) {
    		r = mid;
    	} else {
    		l = mid + 1;
    	}
    }
    std::cout << std::max(0, c - l + 1) << "\n";
}

B. Zmei Gorynich

题意:\(n\)个技能,每个技能造成\(d_i\)点伤害,如果用完这个技能怪物血量大于\(0\)则恢复\(h_i\)的血量,否则游戏结束。怪物一开始有\(x\)血,每个技能随便用。求打败怪物最少使用几次技能。

枚举一直用一个技能,打到怪物血少于最高伤害的技能,然后用这个技能打败怪物。

点击查看代码
void solve() {
    i64 n, x;
    std::cin >> n >> x;
    std::vector<std::pair<i64, i64>> a(n);
    i64 max = 0;
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i].first >> a[i].second;
    	max = std::max(max, a[i].first);
    }

    if (max >= x) {
    	std::cout << 1 << "\n";
    	return;
    }

    i64 ans = 1e18;
    for (auto & [d, h] : a) {
    	if (d <= h) {
    		continue;
    	}

    	ans = std::min(ans, 1 + (x - max + d - h - 1) / (d - h));
    }
    if (ans == 1e18) {
    	ans = -1;
    }
    std::cout << ans << "\n";
}

C. The Number Of Good Substrings

题意:给你一个二进制,求有多少子串满足子串长度等于其代表的数。

如果没有前导零,观察到子串长度大于\(20\)就一定大于字符串长度,于是我们可以暴力枚举。但因为有前导零,我们需要记录当前位置下一个1在哪里,每次从跳到这个1开始枚举。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    std::vector<int> next(n + 1);
    next[n] = n;
    for (int i = n - 1; i >= 0; -- i) {
    	next[i] = next[i + 1];
    	if (s[i] == '1') {
    		next[i] = i;
    	}
    }
    int ans = 0;
    for (int i = 0; i < n; ++ i) {
    	int sum = 0;
    	for (int j = next[i]; j < n && sum <= n; ++ j) {
    		sum = sum * 2 + (s[j] - '0');
    		ans += sum == j - i + 1;
    	}
    }
    std::cout << ans << "\n";
}

D. Coloring Edges

题意:给一个有向图的边染色,使得没有一个环的颜色都一样。求方案。

显然如果没环就是一个颜色。
如果有环,一个环最多两个颜色,且每个环并不影响其它环,所以最多两个颜色。关于方案,如果一条边是小的点连大的点,则染色为1,否则染色为2。因为环里必然有这两种类型的边,所以合法。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<std::vector<int>> adj(n);
    std::vector<int> ans(m), in(n);
    for (int i = 0; i < m; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	if (u < v) {
    		ans[i] = 1;
    	} else {
    		ans[i] = 2;
    	}

    	adj[u].push_back(v);
    	++ in[v];
    }

    std::queue<int> q;
    for (int i = 0; i < n; ++ i) {
    	if (in[i] == 0) {
    		q.push(i);
    	}
    }

    int cnt = 0;
    while (q.size()) {
    	int u = q.front(); q.pop();
    	++ cnt;
    	for (auto & v : adj[u]) {
    		if ( -- in[v] == 0) {
    			q.push(v);
    		}
    	}
    }

    if (cnt != n) {
    	std::cout << 2 << "\n";
    } else {
    	std::cout << 1 << "\n";
    	std::ranges::fill(ans, 1);
    }
	for (int i = 0; i < m; ++ i) {
		std::cout << ans[i] << " \n"[i == m - 1];
	}
}

E. Sum Queries?

题意:给你一个数组,两种操作,一个是改变一个数的值,一个是询问\([l, r]\)的和最小的坏子序列的和。对于一个子序列,记\(sum\)为它的所有元素的和,如果在十进制下每一位都至少有一个元素和和相同,这个子序列就是好,如果有一位不满足,就是坏的。

显然需要有一位至少出现了进位才可能使得这一位是坏的。发现选两个数产生进位就一定是坏的。于是猜测最多选两个数。那么对于某一位,我们需要选两个数满足这一位都非零。
那么只需要给每一位开一个线段树维护最小值和次小值就行。

点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)

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

template <class Info>
struct SegmentTree {
	std::vector<Node<Info> > tr;
	SegmentTree(){}
	SegmentTree(int _n) {
		init(_n);
	}

	SegmentTree(std::vector<Info> & a) {
		init(a);
	}

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

	void init(std::vector<Info> & a) {
		int _n = (int)a.size();
		tr.assign(_n << 2, {});
		build(0, _n - 1, a);
	}

	void pushup(int u) {
		tr[u].info = tr[ls].info + tr[rs].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, ls); build(mid + 1, r, rs);
	}

	void build(int l, int r, std::vector<Info> & a, int u = 1) {
		tr[u] = {l, r, {}};
		if (l == r) {
			tr[u].info = a[l];
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, a, ls); build(mid + 1, r, a, rs);
		pushup(u);
	}

	void modify(int p, Info add, bool set = false) {
		int u = 1;
		while (tr[u].l != tr[u].r) {
			int mid = umid;
			if (p <= mid) {
				u = ls;
			} else {
				u = rs;
			}
		}

		if (set) {
			tr[u].info = add;
		} else {
			tr[u].info = tr[u].info + add;
		}

		u >>= 1;
		while (u) {
			pushup(u);
			u >>= 1;
		}
	}

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

		int mid = umid;
		if (r <= mid) {
			return query(l, r, ls);
		}  else if (l > mid) {
			return query(l, r, rs);
		}

		return query(l, r, ls) + query(l, r, rs);
	}
};

struct Info {
	int min1, min2;
};

Info operator + (const Info & a, const Info & b) {
	Info res{};
	res.min1 = std::min(a.min1, b.min1);
	res.min2 = std::min({std::max(a.min1, b.min1), a.min2, b.min2});
	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];
    }

    i64 p[11]{};
    p[0] = 1;
    for (int i = 1 ; i <= 10; ++ i) {
    	p[i] = p[i - 1] * 10;
    }	

    const int inf = 2e9;
    std::vector<SegmentTree<Info>> tr(10);
	std::vector<Info> info(n);
    for (int i = 0; i < 10; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		int x = a[j] % p[i + 1] / p[i];
    		info[j] = {x == 0 ? inf : a[j], inf};
    	}

    	tr[i].init(info);
    }

    while (m -- ) {
    	int op;
    	std::cin >> op;
    	if (op == 1) {
    		int x, y;
    		std::cin >> x >> y;
    		-- x;
    		for (int i = 0; i < 10; ++ i) {
    			int v = y % p[i + 1] / p[i];
    			tr[i].modify(x, Info{v == 0 ? inf : y, inf}, true);
    		}
    	} else {
    		int l, r;
    		std::cin >> l >> r;
    		-- l, -- r;
    		int ans = -1;
    		for (int i = 0; i < 10; ++ i) {
    			auto [x, y] = tr[i].query(l, r);
    			if (x == inf || y == inf) {
    				continue;
    			}
    			if (ans == -1 || x + y < ans) {
    				ans = x + y;
    			}
    		}
    		std::cout << ans << "\n";
    	}
    }
}
posted @ 2025-04-30 18:43  maburb  阅读(9)  评论(0)    收藏  举报