牛客周赛 Round 101


A. 题解的token计算

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

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::cout << std::fixed << std::setprecision(12);
	std::cout << 150 * std::log(n) << "\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. 76修地铁

按题意计算就行。

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

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::cout << n / 5 * 2 << " " << std::max(0, n - 5) / 10 + (n >= 5) << " " << n / 20 * 3 << " " << n * 2 - n / 20 * 2 << "\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. 76选数

题意:\([1, n]\)中选出一些数异或,求最大的异或和。

\(n\)最高位为\(i\),那么就是\(2^{i+1} - 1\)。因为我们可以取\(2^0, 2^1, ... ,2^i\)。显然这就是最大的了。

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

using i64 = long long;

void solve() {
	i64 n;
	std::cin >> n;
	for (int i = 63; i >= 0; -- i) {
		if (n >> i & 1) {
			std::cout << (1ll << i + 1) - 1 << "\n";
			return;
		}
	}
}

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. 76构造

题意:选择\([1, n]\)的排列,然后分成不超过\(100\)个不相交连续子区间,使得每个区间的\(gcd\)或起来是\(m\)

考虑\(m\)的所有二进制位,\([1, n]\)的每个数选择最大的\(2^i\)作为组,满足\(m\)二进制下第\(i\)位是\(1\)。剩下的就都分一组就行了。然后判断\(m\)的每个二进制下的\(1\)是不是都有数选择了它,再判断或上剩下那一组的\(gcd\)是不是\(m\)就行。

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

using i64 = long long;

void solve() {
	int n, m;
	std::cin >> n >> m;
	std::vector<int> a;
	for (int i = 19; i >= 0; -- i) {
		if (m >> i & 1) {
			a.push_back(1 << i);
			if ((1 << i) > n) {
				std::cout << -1 << "\n";
				return;
			}
		}
	}

	std::vector<std::vector<int>> g(n + 1);
	std::vector<int> st(n + 1);
	for (int i = 1; i <= n; ++ i) {
		for (auto & x : a) {
			if (i % x == 0) {
				g[x].push_back(i);
				st[i] = 1;
				break;
			}
		}
	}

	int d = 0;
	for (int i = 1; i <= n; ++ i) {
		if (!st[i]) {
			g[0].push_back(i);
			d = std::gcd(d, i);
		}
	}

	if ((m & d) != d) {
		std::cout << -1 << "\n";
		return;
	}

	for (int i = 0; i < 20; ++ i) {
		if (m >> i & 1) {
			if (g[1 << i].empty()) {
				std::cout << -1 << "\n";
				return;
			}
		}
	}

	std::vector<int> p;
	std::vector<std::pair<int, int>> ans;
	for (int i = 0; i <= n; ++ i) {
		if (g[i].empty()) {
			continue;
		}

		int l = p.size();
		for (auto & x : g[i]) {
			p.push_back(x);
		}

		ans.emplace_back(l, (int)p.size() - 1);
	}

	for (int i = 0; i < n; ++ i) {
		std::cout << p[i] << " \n"[i == n - 1];
	}

	std::cout << ans.size() << "\n";
	for (auto & [l, r] : ans) {
		std::cout << l + 1 << " " << r + 1 << "\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. qcjj寄快递

直接给题面:
给定 \(n\) 个点,每个相邻点对之间有一个欧式距离 \(e_i = \sqrt{ (x_i - x_{i-1})^2 + (y_i - y_{i-1})^2 }\) ,耗时为 \(t_i = 2 \cdot k_i + 2 \cdot e_i / 2^{k_i}\)
你需要最小化 \(\sum_{i=2}^{n} t_i\) ,并输出之。
其中,\(k_i\) 是你自己选定的非负浮点数,对于不同的 \(i\) 可以有不同的 \(k_i\)

猜测可以三分。

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

using i64 = long long;

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

	double ans = 0;
	for (int i = 0; i + 1 < n; ++ i) {
		double dx = x[i] - x[i + 1], dy = y[i] - y[i + 1];
		double e = std::sqrt(dx * dx + dy * dy);

		auto get = [&](double k) -> double {
			return 2 * k + 2 * e / std::pow(2, k);
		};

		double l = 0, r = 60;
		double min = 1e18;
		for (int t = 0; t < 100; ++ t) {
			double mid1 = l + (r - l) / 3, mid2 = l + (r - l) * 2 / 3;
			double v1 = get(mid1), v2 = get(mid2);
			if (v1 <= v2) {
				r = mid2;
				min = std::min(min, v1);
			} else {
				l = mid1;
				min = std::min(min, v2);
			}
		}

		ans += min;
	}
	std::cout << std::fixed << std::setprecision(12);
	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;
}

F. 幂中幂plus

题意:给定\(c_0, base, mod\)\(c_i = pow(base, c_{i-1}) \% mod\)\(q\)次询问,每次求\((\sum_{i=1}^{k} c_i) \%mod\)

一个结论是,会出现循环节(不会证)。
那么找出这个循环节的位置,每次询问讨论一下,用前缀和就可以写了。

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

using i64 = long long;

i64 power(i64 a, i64 b, i64 mod) {
	i64 res = 1;
	for (;b; b >>= 1, a = a * a % mod) {
		if (b & 1) {
			res = res * a % mod;
		}
	}
	return res;
}

void solve() {
	i64 base, c0, mod;
	std::cin >> base >> c0 >> mod;
	int n = mod;
	std::vector<i64> c(n + 1);
	c[0] = c0;
	base %= mod;
	for (int i = 1; i <= n; ++ i) {
		c[i] = power(base, c[i - 1], mod);
	}

	std::map<i64, int> mp;
	int l = 0, r = 0;
	for (int i = 1; i <= n; ++ i) {
		if (mp.count(c[i])) {
			l = mp[c[i]];
			r = i - 1;
			break;
		}
		mp[c[i]] = i;
	}

	std::vector<i64> sum(n + 1);
	for (int i = 1; i <= n; ++ i) {
		sum[i] = (sum[i - 1] + c[i]) % mod;
	}

	int q;
	std::cin >> q;
	while (q -- ) {
		i64 x;
		std::cin >> x;
		if (x < l) {
			std::cout << sum[x] << "\n";
		} else {
			i64 ans = sum[l - 1];
			x -= l - 1;
			i64 s = (sum[r] - sum[l - 1] + mod) % mod;
			ans = (ans + x / (r - l + 1) % mod * s % mod) % mod;
			ans = (ans + sum[l - 1 + x % (r - l + 1)] - sum[l - 1] + mod) % mod;
			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-20 21:01  maburb  阅读(62)  评论(0)    收藏  举报