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;
}
}
}
点击查看代码
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;
}
浙公网安备 33010602011771号