Step1 Problem:
n = a*b, 同时 a 的因数不存在平方数,b 的因数不存在平方数。(a != b,a 和 b 互换位置算不同的方案)
f(n):满足上述条件的方案数
例如 n = 4: 只有 (2, 2) 一种方案,因为 (1, 4), (4, 1) 中的 4 的因数存在平方数。
T组询问,每次给你一个 n, 让你输出 sum{ f(i) }, i = 1, 2, 3, …, n.
数据范围:
T<=20, n <= 2e7.
Step2 Ideas:
线性筛核心思路:保证每个合数只会被它的最小质因数筛去
我们线性求出 f(i), 预处理一波前缀和。
如何求 f(i):
如果 i 是质素:f(i) = 2
如果 i 不是质素:
我们求出 i 的最小质因数 p:
如果 p 的幂 = 1:f(i) = f(i/p) * 2;// p 可以放在小因数 或者 大因数 所以乘 2
如果 p 的幂 = 2:f(i) = f(i/(p^2));// p 得分开放在小因素 大因数那
如果 p 的幂 > 2:f(i) = 0;// 无论怎么放,因数都肯定包含平方数
线性筛的过程中,所有的合数我们都可以访问一遍,在访问的过程同时知道最小的质因数
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e7+5;
int prim[N], ans[N], cnt = 0;
bool vis[N];
void get_prim()
{
memset(vis, 0, sizeof(vis));
vis[0] = vis[1] = 1;
ans[1] = 1;
for(int i = 2; i < N; i++)
{
if(!vis[i]) {
prim[cnt++] = i;
ans[i] = 2;
}
for(int j = 0; j < cnt && prim[j]*i < N; j++) {//枚举 i 的最小质因数
vis[prim[j]*i] = 1;
if(i%prim[j] == 0) {//再往后就不是 i 的最小质因数了
int t = i/prim[j];
if(t%prim[j] == 0) {
ans[i*prim[j]] = 0;
}
else ans[i*prim[j]] = ans[t];
break;
}
else {
ans[prim[j]*i] = ans[i]*2;
}
}
}
ans[0] = 0;
for(int i = 1; i < N; i++) {
ans[i] += ans[i-1];
}
}
int main()
{
int T, n;
get_prim();
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
printf("%d\n", ans[n]);
}
return 0;
}