E. Rasta Thamaye Dilo
要从村庄i走到任意村庄j(i,j属于2,3,... ,n),就要把2~n的村庄连在一起。如果i%j=0或j%i=0,那这两个村庄本来就是连接在一起的。
那么我们要计算的就是有几个没在一起的村庄群,连起来需要的最小边数即为答案。

那么什么情况下村庄没在一起呢?
村庄群内各个村庄编号和另一个村庄群内各个村庄编号互不能整除。

质数与其倍数必然是联通的,比如一个质数m,最早有路是在 <2,m> -> 2*m 时且若 z < m 则 2 * z < 2 * m,可由此推出 数字2 可以作为一个中介,将 n / 2 及小于 n / 2 的村庄连成一个村庄群,大于 n / 2 的非质数的归到其因子下,是质数的单独开一个堆。

故解题流程为
1.埃氏筛选法记录质数

点击查看代码
//先假设他们都是质数,在下面出现是质数倍数的筛掉
vector<int>pre(M,1);
//计算2,3,.. ,M是不是质数,M是判断是不是质数这些数里的最大值
for (int i = 2;i < M;++i) {
//已知2一定是质数,因为 i*倍数 是递增的,所以最近的合数一定是这个质数的倍数
	if (pre[i]) {
//筛掉合数,j+=i非常之妙 从 2*i 开始加上i 算i的倍数
		for (int j = i * 2;j < M;j += i) {
			pre[j] = 0; 
		}
	}
}
2.**前缀和**记录前n个质数个数
点击查看代码
prime[i] += prime[i - 1];

3.prefix[n]-prefix[n/2]即为要建立的最小数

特判:当n<=3时,n/2=1 ,没有村庄编号为 1。所以这个情况算法是 结点数-1。

点击查看代码
#include<iostream>
#include<vector>
using namespace std;
const int M = 1e7;
int main()
{
	vector<int>prime(M + 1, 1);
	prime[0] = 0, prime[1] = 0;
	for (int i = 2;i <= M;i++) {
		if (prime[i]) {
			for (int j = 2 * i;j <= M;j+=i) {
				prime[j] = 0;
			}
		}
	}
	for (int i = 1;i <= M;i++) {
		prime[i] += prime[i - 1];
	}
	cout << prime[6];
	int t;
	cin >> t;
	while (t--) {
		int m;
		cin >> m;
		if (m <= 3) cout << m - 2 << endl;
		else 
		cout << prime[m] - prime[m / 2] << endl;
	}
	return 0;
}
posted on 2025-10-08 18:51  一方见地  阅读(13)  评论(0)    收藏  举报