230512 // 数论

夺,夺少?哦,85pts,小让一手。

什么?GM 居然还没讲过欧拉函数?震惊!


A. 征兵

http://222.180.160.110:1024/contest/3574/problem/1

GM 说,怕久了不打最小生成树我们给忘了。

笑话,就算退役十年我也不一定能忘了 Kruskal,就算在役十年我也不一定能记住 Prim。

就一板板题,没什么好说的。

#define int long long
namespace XSC062 {
using namespace fastIO;
const int cos = 1e4;
const int maxn = 2e4 + 5;
const int maxm = 5e4 + 5;
struct _ {
	int u, v, w;
	bool operator< (const _ &q) const {
		return w > q.w;
	}
};
_ t[maxm];
int f[maxn];
int T, n, m, r, res;
inline void Init(int n) {
	for (int i = 1; i <= n; ++i)
		f[i] = i;
	return;
}
int find(int x) {
	return x == f[x] ? x : f[x] = find(f[x]);
}
inline void merge(int x, int y) {
	f[find(x)] = find(y);
	return;
}
int main() {
	read(T);
	while (T--) {
		read(n), read(m), read(r);
		for (int i = 1; i <= r; ++i) {
			read(t[i].u), read(t[i].v);
			t[i].v += n, read(t[i].w);
			++t[i].u, ++t[i].v;
		}
		std::sort(t + 1, t + r + 1);
		Init(n += m), res = n * cos;
		for (int i = 1; i <= r; ++i) {
			int fx = find(t[i].u);
			int fy = find(t[i].v);
			if (fx == fy)
				continue;
			merge(t[i].u, t[i].v);
			res -= t[i].w;
		}
		print(res, '\n');
	}
	return 0;
}
} // namespace XSC062
#undef int

B. 欧拉函数的值

http://222.180.160.110:1024/contest/3574/problem/2

嘶,太久没碰数学,欧拉函数是啥?小尴一个尬。

哦哦,看完样例懂了,\(n\) 以内和 \(n\) 互质的数个数对吧。好像是用筛法求的来着。现场推一下吧。

列表可以简单地发现,若 \(n={d_1}^{p_1}\times {d_2}^{p_2} \times \cdots \times {d_k}^{p_k}\),则 \(\phi(n) = (d_1-1)\times {d_1}^{p_1-1} \times (d_2-1)\times {d_2}^{p_2-1}\times \cdots \times (d_k-1)\times {d_k}^{p_k-1}\)。所以打个根号算法即可。

namespace XSC062 {
using namespace fastIO;
int n;
inline int phi(int n) {
	int res = 1;
	for (int i = 2; i * i <= n; ++i) {
		if (n % i == 0) {
			res *= i - 1;
			n /= i;
			while (n % i == 0)
				res *= i, n /= i;
		}
	}
	if (n > 1)
		res *= n - 1;
	return res;
}
int main() {
	read(n);
	while (n) {
		print(phi(n), '\n');
		read(n);
	}
	return 0;
}
} // namespace XSC062

C. 龙哥的问题

http://222.180.160.110:1024/contest/3574/problem/3

龙哥 /se

不难想到,根号枚举 \(n\) 的每个因数(注意不是质的),因为任何数和 \(n\) 的最大公约数都应该是 \(n\) 的因数之一,所以我们对于因数 \(p\),求得 \(1\sim n\) 中有多少个 \(i\)\(n\) 的最大公约数是 \(p\) 即可。

那么这个数量怎么求呢?很明显,如果 \(\gcd\left(n,i\right)=p\),那么 \(\gcd\left(\dfrac np, \dfrac ip\right) = 1\)

因为 \(i\le n\),所以 \(\dfrac ip\le \dfrac np\),所以满足 \(\gcd\left(\dfrac np, \dfrac ip\right) = 1\)\(i\) 的数量就是 \(\phi\left(\dfrac np\right)\) 的值。

#define int long long
namespace XSC062 {
using namespace fastIO;
int n;
inline int phi(int n) {
	int res = 1;
	for (int i = 2; i * i <= n; ++i) {
		if (n % i == 0) {
			res *= i - 1;
			n /= i;
			while (n % i == 0)
				res *= i, n /= i;
		}
	}
	if (n > 1)
		res *= n - 1;
	return res;
}
inline int Solve(int n) {
	int res = 0;
	for (int i = 1; i * i <= n; ++i) {
		if (n % i)
			continue;
		res += i * phi(n / i);
		if (i * i == n)
			continue;
		int j = n / i;
		res += j * phi(n / j);
	}
	return res;
}
int main() {
	read(n);
	print(Solve(n));
	return 0;
}
} // namespace XSC062
#undef int

D. 可见的点(加强版)

http://222.180.160.110:1024/contest/3574/problem/4

不难发现,对于点 \((x, y)\),若 \(\gcd(x,y)\ne 1\),则其可见(注意坐标从 0 开始)。

对于每一个 \(x\),求得其 phi 值即可。注意到 \(x\) 是连续的,且我们对时间复杂度的需求是 \(\mathcal O(n)\),使用欧拉筛进行预处理即可。如果乐意可以再加个前缀和(注意到两坐标的对称性,答案为 \(2\times S(\phi(1\sim n)) - 1\))。

#define int long long
namespace XSC062 {
using namespace fastIO;
const int lim = 1e6;
const int mod = 1e9 + 7;
const int maxm = 1e6 + 5;
const int maxn = 1e6 + 5;
bool u[maxn];
int T, n, cnt, _t;
int p[maxm], phi[maxn];
inline void getPhi(int n) {
	phi[1] = 1;
	u[0] = u[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!u[i]) {
			p[++cnt] = i;
			phi[i] = i - 1;
		}
		for (int j = 1; j <= cnt &&
						p[j] * i <= n; ++j) {
			u[p[j] * i] = 1;
			phi[p[j] * i] = phi[p[j]] * phi[i];
			if (i % p[j] == 0) {
				phi[p[j] * i] = phi[i] * p[j];
				break;
			}
		}
	}
	return;
}
int main() {
	read(T);
	getPhi(lim);
	for (int i = 1; i <= lim; ++i)
		(phi[i] += phi[i - 1]) %= mod;
	while (T--) {
		read(n);
		print(++_t, ' ');
		print(n, ' ');
		print((2 * phi[n] + 1) % mod, '\n');
	}
	return 0;
}
} // namespace XSC062
#undef int

G. 线性筛素数

http://222.180.160.110:1024/contest/3574/problem/7

给我十年我都不一定忘得掉欧拉筛…… woc,打挂了。还好一眼就看出来了错在哪里。

namespace XSC062 {
using namespace fastIO;
const int maxm = 5e7 + 5;
const int maxn = 1e8 + 5;
int p[maxm];
bool u[maxn];
int n, m, cnt;
inline void Euler(int n) {
	u[0] = u[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!u[i])
			p[++cnt] = i;
		for (int j = 1; j <= cnt &&
						p[j] * i <= n; ++j) {
			u[p[j] * i] = 1;
			if (i % p[j] == 0)
				break;
		}
	}
	return;
}
int main() {
	read(n), read(m);
	Euler(n);
	while (m--) {
		read(n);
		puts(u[n] ? "No" : "Yes");
	}
	return 0;
}
} // namespace XSC062
posted @ 2023-05-12 18:55  XSC062  阅读(47)  评论(0编辑  收藏  举报