Educational Codeforces Round 66 (Rated for Div. 2) A~F

A - From Hero to Zero

模拟。

能除 \(k\) 直接除 \(k\),否则减掉余数部分。

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

using i64 = long long;

void solve() {

    i64 n, k;
    std::cin >> n >> k;
    
    i64 ans = 0;
    while(n){
    	while(n && n % k == 0){
    		n /= k;
    		ans += 1;
    	}
    	ans += n % k;
    	n -= n % k;
    }

    std::cout << ans << "\n";

}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

B - Catch Overflow!

模拟。

用栈维护每次操作的和,碰到 end 就把前一个 for 到现在的和取出来乘以该次的循环次数,溢出直接退出即可。

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

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;

	i64 x = (1LL << 32) - 1;
	std::stack<std::array<i64,2>> st;
	std::vector<std::array<int,2>> num;
	for(int i = 0; i < n; i += 1) {
		std::string s;
		std::cin >> s;

		if(s == "add") {
			st.push({1, i});
		} else if(s == "for") {
			int a;
			std::cin >> a;
			num.push_back({a, i});
		} else {
			i64 tmp = 0;
			while(st.size() && st.top()[1] >= num.back()[1]) {
				tmp += st.top()[0];
				st.pop();
			}
			auto k = num.back()[0];
			num.pop_back();
			if(tmp * k > x) {
				std::cout << "OVERFLOW!!!\n";
				return 0;
			}
			st.push({tmp * k, i});
		}
	}

	i64 now = 0;
	while(st.size()) {
		now += st.top()[0];
		st.pop();
		if(now > x) {
			std::cout << "OVERFLOW!!!\n";
			return 0;
		}
	}

	std::cout << now << "\n";

	return 0;
}

C - Electrification

枚举。

\(|a_i-x|\) 表示 \(a_i\)\(x\) 的距离,那么找离 \(k+1\) 近的距离就是离它第 \(k+1\) 近的点,则前面 \(k\) 个点都是 \(x\) 两周形成了一段连续的区间。

假设离 \(x\) 最近的 \(k\) 个点为 \(a_i,..,a_{i+k-1}\),那么第 \(k+1\) 小的距离就在两端,即 \(f_k(x)=\min(x-a_{i-1},a_{i+k}-x)\),也就是说可以枚举 \(k+1\) 长度的区间,那么这个第 \(k+1\) 点要么是 \(a_i\),要么是 \(a_{i+k}\),选取最小的一个即可,那么位置就是 \(a_i+\frac{a_{i+k}-a_i}2\)

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

using i64 = long long;

void solve() {

	int n, k;
	std::cin >> n >> k;

	int ans = -1, l = INT_MAX;
	std::vector<int> a(n);
	for(int i = 0; i < n; i += 1) {
		std::cin >> a[i];
		if(i >= k) {
			int j = i - k, d = (a[i] - a[j]);
			if(d < l){
				l = d;
				ans = a[j] + d / 2;
			}
		}
	}

	std::cout << ans << "\n";

}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int t;
	std::cin >> t;
	while (t--) {
		solve();
	}

	return 0;
}

D - Array Splitting

数学。

\(S_k=\sum_{i=k}^na_i\) 表示为从 \(k\)\(n\) 的后缀和,\(p_i\) 表示第 \(i\) 个子数组的起点下标,显然有 \(p_1=1,p_i<p_{i+1}\)

那么 \(\sum\limits_{i=1}^{n} (a_i \cdot f(i))=1\cdot(S_{p_1}-S_{p_2})+2\cdot(S_{p_2}-S_{p_3})+\cdots+k\cdot (S_{p_k}-0)\),拆开得 \(S_{p_1}+(2-1)S_{p_2}+(3-2)S_{p_3}+\cdots+(k-(k-1))S_{p_k}=S_{p_1}+S_{p_2}+S_{p_3}+\cdots+S_{p_k}\),显然,除了 \(p_1\) 是固定的,其他的 \(S_{p_2\sim p_k}\) 是可以任意选择的,所以预处理 \(S_i\),选取前 \(k-1\) 大的 \(S_{2\sim n}\) 再加上 \(S_1\) 即可。

参考[1]

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

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, k;
    std::cin >> n >> k;

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

    std::vector<i64> p(n);
    for(int i = n - 1;i >= 0;i -= 1){
    	p[i] = a[i];
    	if(i < n - 1){
    		p[i] += p[i + 1];
    	}
    }

    sort(p.begin() + 1, p.end(), std::greater<>());

    i64 ans = 0;
    for(int i = 0;i < k;i += 1){
    	ans += p[i];
    }

    std::cout << ans << "\n";

    return 0;
}

E - Minimal Segment Cover

倍增。

\(f_{i,k}\) 为从 \(i\) 跑了 \(2^k\) 步最远到达的距离,那么初始可以用指针维护每个坐标能到达的最远距离即可,不能到达的用 \(-1\) 表示。

最后判断的时候先判断 \(f_{i,k}<r\)再去跳,不断地逼近 \(r\),判断大于等于 \(r\) 可能会一次性跳很多之类的,最后跳到 \(x\) 位置,再看 \(x\) 能不能到达 \(r\),能的话再单独跳一次即可。

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

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n, m;
	std::cin >> n >> m;

	int max = 0;
	std::vector<std::array<int,2>> a(n);
	for(auto &[l, r] : a) {
		std::cin >> l >> r;
		max = std::max(max, r);
	}

	sort(a.begin(), a.end());

	int j = 0, now = -1;
	std::vector<std::array<int,21>> f(max + 1);
	for(int i = 0; i <= max; i += 1) {
		if(i >= now) {
			now = -1;
		}
		while(j < n && i >= a[j][0]) {
			now = std::max(now, a[j][1]);
			j += 1;
		}
		f[i][0] = now;
	}

	for(int j = 1; j <= std::__lg(max) + 1; j += 1) {
		for(int i = 0; i <= max; i += 1) {
			if(f[i][j - 1] == -1) {
				f[i][j] = -1;
				continue;
			}
			f[i][j] = f[f[i][j - 1]][j - 1];
		}
	}

	while(m --) {
		int l, r;
		std::cin >> l >> r;

		if(r > max) {
			std::cout << "-1\n";
			continue;
		}

		int ans = 0;
		for(int i = std::__lg(max) + 1; i >= 0; i -= 1) {
			if(f[l][i] < r && ~f[l][i]) {
				l = f[l][i];
				ans += 1 << i;
			}
		}

		if(f[l][0] == -1) {
			std::cout << "-1\n";
			continue;
		}

		if(f[l][0] >= r) {
			ans += 1;
		}
		std::cout << ans << "\n";
	}

	return 0;
}

F - The Number of Subpermutations

异或哈希。

一个区间 \([l,r]\) 要满足是一个 \(1\sim r-l+1\) 的排列,有两个条件可以确定即这个区间所有的数都不重复,并且区间最大值为 \(r-l+1\)

\(1\sim n\) 都赋值一个随机数,再维护一个前缀异或和就可以快速的判定一个区间是否满足要求。

具体地,从 \(1\) 向两边扩展,维护扩展时的最大值 \(x\),如果满足 \([i,i-x+1]\) 的异或和是上面 \(x\) 的前缀异或和即为找到一个答案;可以先从 \(1\) 向右找,然后翻转 \(a\) 再进行一遍即可,最后减掉多算的 \(1\)

其他做法线段树加单调栈,分治,可以参考[2]

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

using i64 = long long;
using u64 = unsigned long long;

std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;

	std::vector<int> val(n + 1), a(n), c(n + 1);
	for(int i = 0; i < n; i += 1) {
		std::cin >> a[i];
		c[i + 1] = val[i + 1] = rng();
		c[i + 1] ^= c[i];
	}

	i64 ans = 0;
	auto work = [&]()->void{
		std::vector<int> p(n + 1);
		int max = 0;
		for(int i = 0; i < n; i += 1) {
			p[i + 1] = val[a[i]];
			p[i + 1] ^= p[i];
			if(a[i] == 1) {
				max = 1;
			}
			max = std::max(max, a[i]);
			if(i + 1 >= max && (p[i + 1] ^ p[i + 1 - max]) == c[max]) {
				ans += 1;
			}
		}
	};

	work();
	reverse(a.begin(), a.end());
	work();

	ans -= std::count(a.begin(), a.end(), 1);

	std::cout << ans << "\n";

	return 0;
}

  1. https://codeforces.com/blog/entry/67484 ↩︎

  2. https://www.cnblogs.com/tzcwk/p/Codeforces-1175F.html ↩︎

posted @ 2025-10-25 21:08  Ke_scholar  阅读(2)  评论(0)    收藏  举报