pta天梯赛L3部分题解

可怜的简单题

题意

我们有一个随机过程:

  1. 初始数列 \(A\) 为空。
  2. 从区间 \([1, n]\) 中均匀随机选择一个整数 \(i\) 加入 \(A\)
  3. 如果存在大于 1 的正整数 \(w\) 使得 \(A\) 中所有元素都是 \(w\) 的倍数(即 \(\gcd(A) > 1\)),则返回步骤 2 继续添加元素。
  4. 否则(\(\gcd(A) = 1\)),停止并返回 \(A\)

求停止时数列 \(A\) 的期望长度,结果对质数 \(p\) 取模(\(p > n\))。

思路

\(f(d,x)\) 为序列的前 \(x\)\(gcd\)\(d\) 整除的概率。
\(g(d,x)\) 为序列的前 \(x\)\(gcd\)\(d\) 的概率。
不难得出 \(f(d,x)=(\frac{\lfloor \frac{n}{d}\rfloor}{n})^x.\)
\(\displaystyle f(d,x)=\sum_{d|k}g(k,x).\)
\(\iff\displaystyle g(d,x)=\sum_{d|k}\mu(\frac{k}{d})\cdot f(k,x).\)
\(\displaystyle g(1,x)=\sum^{n}_{k=1}\mu(k)\cdot f(k,x)=\sum^{n}_{k=1}\mu(k)\cdot(\frac{\lfloor \frac{n}{k}\rfloor}{n})^x.\)
那序列长度大于 \(x\) 的概率为 \(\displaystyle P(x)=1-g(1,x)=1-\sum^{n}_{k=1}\mu(k)\cdot(\frac{\lfloor \frac{n}{k}\rfloor}{n})^x\)
\(\displaystyle =-\sum^{n}_{k=2}\mu(k)\cdot(\frac{\lfloor \frac{n}{k}\rfloor}{n})^x\)
则序列的期望长度为
\(\displaystyle E=\sum^{\infty}_{x=0}P(x)=1-\sum^{\infty}_{x=1}\sum^{n}_{k=2}\mu(k)\cdot(\frac{\lfloor \frac{n}{k}\rfloor}{n})^x\)
\(\displaystyle =1-\sum^{n}_{k=2}\mu(k)\sum^{\infty}_{x=1}(\frac{\lfloor \frac{n}{k}\rfloor}{n})^x=1 -\sum^{n}_{k=2}\mu(k)(\frac{\lfloor \frac{n}{k}\rfloor}{n-\lfloor \frac{n}{k}\rfloor})\)
用数论分块和杜教筛即可求解。

代码

点击查看代码
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define double long double
#define PII pair<int,int>
#define PIV pair<int,vector<int>>
#define PIII pair<int,PII>
#define LL __int128
const int N = 2e6 + 10, INF = 1e18;
int mod = 998244353;
const int M = 4e2 + 10;
const double eps = 1e-6;

LL qpow(LL x, int n) {
	LL ans = 1;
	while (n) {
		if (n & 1) {
			ans *= x;
			ans %= mod;
		}
		x *= x;
		x %= mod;
		n >>= 1;
	}
	return ans;
}
int fac[N], inv[N];
void fact(int K) {
	fac[0] = 1;
	for (int i = 1; i <= K; ++i) fac[i] = fac[i - 1] * i % mod;
	inv[K] = qpow(fac[K], mod - 2);
	for (int i = K - 1; i >= 0; --i) inv[i] = inv[i + 1] * (i + 1) % mod;
}
int C(int n, int k) {
	if (k < 0 || k > n) return 0;
	return fac[n] * inv[k] % mod * inv[n - k] % mod;
}
constexpr int MAXN = 5000010;
long long T, n, pri[MAXN], cur, mu[MAXN], sum_mu[MAXN];
bool vis[MAXN];
map<long long, long long> mp_mu;

long long S_mu(long long x) {  // 求mu的前缀和
	if (x < MAXN) return sum_mu[x];
	if (mp_mu[x]) return mp_mu[x];  // 如果map中已有该大小的mu值,则可直接返回
	long long ret = (long long)1;
	for (long long i = 2, j; i <= x; i = j + 1) {
		j = x / (x / i);
		ret -= S_mu(x / i) * (j - i + 1);
	}
	return mp_mu[x] = ret;  // 路径压缩,方便下次计算
}

long long S_phi(long long x) {  // 求phi的前缀和
	long long ret = (long long)0;
	long long j;
	for (long long i = 1; i <= x; i = j + 1) {
		j = x / (x / i);
		ret += (S_mu(j) - S_mu(i - 1)) * (x / i) * (x / i);
	}
	return (ret - 1) / 2 + 1;
}

void init(){
	mu[1] = 1;
	for (int i = 2; i < MAXN; i++) {  // 线性筛预处理mu数组
		if (!vis[i]) {
			pri[++cur] = i;
			mu[i] = -1;
		}
		for (int j = 1; j <= cur && i * pri[j] < MAXN; j++) {
			vis[i * pri[j]] = true;
			if (i % pri[j])
				mu[i * pri[j]] = -mu[i];
			else {
				mu[i * pri[j]] = 0;
				break;
			}
		}
	}
	for (int i = 1; i < MAXN; i++)
		sum_mu[i] = sum_mu[i - 1] + mu[i];  // 求mu数组前缀和
}

int H(int n){
	LL res=0;
	int l=2,r;
	while(l<=n){
		r=n/(n/l);
		res+=(S_mu(r)-S_mu(l-1)+mod)%mod*((LL)(n/l)*qpow((n-n/l),mod-2)%mod)%mod;
//		cout<<l<<' '<<r<<' '<<(S_mu(r)-S_mu(l-1)+mod)%mod<<' '<<((n/l)/(n-n/l))%mod<<endl;
		res%=mod;
		l=r+1;
	}
	return res;
}


void solve() {
	init();
	int n, p;
	cin>>n>>mod;
	cout<<(mod+1-H(n))%mod<<endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}


posted @ 2026-03-08 19:12  ptlks  阅读(30)  评论(0)    收藏  举报