2025.2.20 CW 模拟赛

题面 & 题解

T1

算法

概率, 期望.

思路

根据期望的线性性, 可得第 1 堆石子被取走的期望时间 \(\displaystyle E(t) = 1 + \sum_{i = 2}^n P_i\), 其中 \(P_i\) 指的是第 \(i\) 堆石子在「第 1 堆石子被取走前」取走的概率.

注意到 \(P_i\) 只与第 1 堆和第 \(i\) 堆石子有关, 因此相当于只考虑这两堆的情况, 即 \(\displaystyle P_i = \frac{a_i}{a_1 + a_i}\).

这样最后的答案即为 \(\displaystyle 1 + \sum_{i = 2}^{n} \frac{a_i}{a_1 + a_i}\), 时间复杂度 \(\mathcal{O}(n)\).

double ans = 1;
for (int i = 2; i <= n; ++i)
	ans += 1.0 * a[i] / (a[i] + a[1]);

T2

算法

二分.

思路

发现 \(m \le 1000\), 我们可以考虑枚举每一个 \(x\), 再二分查找最小的最大值, \(\rm{check}\) 时贪心即可. 时间复杂度 \(\Theta (nm\log n)\).

将原序列随机打乱再遍历, 令答案为 \(ans - 1\)\(\rm{check}\), 判断当前 \(x\) 是否满足条件. 这样只会二分 \(\mathcal{O}(\ln n)\) 次, 总时间复杂度 \(\mathcal{O}(nm + n \ln n \log n)\).


T3

算法

质因数分解, 容斥.

思路

首先可以知道若一个数不为 \(n\) 的约数, 如果将其选入子集, 那么 \(\rm{lcm}\) 一定不为 \(n\). 于是我们只有在 \(n\) 的因数中选择并加入子集.

现在考虑 \(\gcd = 1, \rm{lcm} = n\) 两个约束. 我们令 \(\displaystyle n = \prod p_i^{\alpha_i}\), 如果集合 \(\mathbb{S}\)\(\gcd\) 为 1, 那么对于每一个 \(p_i\) 均存在至少一个数在 \(p_i\) 中是 0 次方; 同理 \(\rm{lcm}\)\(n\), 代表对于每一个 \(p_i\) 均存在至少一个数在 \(p_i\) 中是 \(\alpha_i\) 次方.

不妨设 \(\omega(n)\)\(n\) 所含有的质因子个数, 显然, 当 \(n \le 10^{18}, \omega(n) \le 15\). 正难则反, 我们考虑使用容斥计算方案数. 具体的, 我们用所有情况去掉不存在 0 次方的情况, 再去掉不存在 \(\alpha\) 次方的情况, 最后加上都不存在的情况即可. 这样, 对于每一个质因子, 我们需要枚举 4 种情况, 总时间复杂度 \(\mathcal{O}(\sqrt n + 4^{\omega(n)} \cdot \omega(n))\).

事实上, 对于质因子情况的枚举是可以优化的. 对于不存在 0 次方 / 不存在 \(\alpha\) 次方的情况是完全等价的, 所以我们只需要枚举一种再在统计答案的时候加上即可. 这样枚举的复杂度降为了 \(\mathcal{O}(3^{\omega(n)} \cdot \omega(n))\), 可以过掉 \(n \le 10^{15}\).

而对于 \(n \le 10^{18}\), 瓶颈就在于分解质因数了. 我们考虑先分解出 \(\sqrt[3]{n}\) 以内的质因数, 剩下的部分只会有 \(p, p ^ 2, pq\) 三种情况, 其中 \(p, q\) 均为素数. 我们使用素性测试判断第一种情况, 再开根判断第二种情况, 那么剩下的就是第三种了. 时间复杂度 \(\mathcal{O}(\sqrt[3]{n} + 3^{\omega(n)} \cdot \omega(n) \cdot \log n)\), 其中带的 \(\log n\) 是因为快速幂, 也可以光速幂 \(\mathcal{O}(\sqrt p)\) 预处理 \(\mathcal{O}(1)\)​ 查询.

#include "iostream"
#include "cmath"
#include "random"
#include "vector"

using namespace std;

typedef long long ll;

constexpr int mod = 998244353;
constexpr int pow3[] = {1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969, 14348907};

ll n;
vector<int> v;

ll qpow(ll x, ll y, const ll Mod = mod) {
	ll ans = 1;
	for (; y; y >>= 1, x = (__int128)x * x % Mod) if (y & 1) ans = (__int128)ans * x % Mod;
	return ans;
}

bool check(ll x) {
	mt19937_64 rnd(time(0));
	if (x < 3) return x == 2; 
	for (int i = 1; i <= 20; ++i) {
		ll t = rnd() % (n - 2) + 2;
		if (qpow(t, x - 1, x) ^ 1) return false;
	}
	return true;
}

void deal(ll x) {
	ll t = round(sqrt(x));
	if (t * t == x) {
		v.push_back(2);
		return;
	}
	v.push_back(1);
	if (!check(x)) v.push_back(1);
}

void init() {
	cin >> n;
	ll t = n;
	if (n > 1e15) {
		for (int i = 2, c, lim = cbrt(n); i <= lim; ++i)
			if (!(t % i)) {
				c = 0;
				while (!(t % i)) ++c, t /= i;
				v.push_back(c);
			}
		if (t > 1) deal(t);
	}
	else {
		for (int i = 2, c, lim = sqrt(n); i <= lim; ++i)
			if (!(t % i)) {
				c = 0;
				while (!(t % i)) ++c, t /= i;
				v.push_back(c);
			}
		if (t > 1) v.push_back(1);
	}
}

void calculate() {
	int sz = v.size(), ans = 0;
	for (int i = 0, lim = qpow(3, sz); i < lim; ++i) {
		int c = 1, t = 1, cnt = 0, c1 = 0;
		for (int j = 0, pw, tmp; j < sz; ++j) {
			pw = v[j], tmp = i / pow3[j] % 3;
			t = 1ll * t * (pw + 1 - tmp) % mod;
			cnt += tmp, c1 += tmp == 1;
		}
		if (cnt & 1) c = -1;
		ans = (ans + c * qpow(2, t + c1) + mod) % mod;
	}
	cout << ans << '\n';
}

void solve() {
	init();
	calculate();
}

int main() {
	solve();
	return 0;
}
posted @   Steven1013  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示