题意:
f(n) 为 n 分解为 a*b 的组数,其中ab均不含有平方因子,a * b 与 b * a 为不同的两组
若n为质数,可以得到 f(n) = 2
若n为合数,设 p 为 n 的一个质因数,令 n = p * q
假如 q 能被 p*p 整除,则说明n中含有三个或三个以上的 p 则f(n) 必然为0,因为要把3个p分为两份其中有一份必然含有两份,即为平方数。
假如 q 能被 p 整除 不能被 p*p整除,说明 n 中有两个 p 分为两份后各自一边,f(n) = f(q/p)
若 q 不能被 p 整除,则在 f(q) 的方案中,可以选择任意一边放入 p,所以 f(n) = f(q) * 2
所以主要的任务就是快速找到每个数的一个质因子,可以在求素数筛时同时找
利用埃氏筛会超时,所以用线性筛
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
typedef long long int LL;
const int N = 2e7 + 10;
LL ans[N], su[N],cnt;
bool isprime[N];
void prime()
{
cnt = ans[1] = 1;
memset(isprime,1,sizeof(isprime));
isprime[0] = isprime[1] = 0;
for(LL i=2;i<N;i++)
{
if(isprime[i]) {su[cnt++] = i; ans[i] = 2;}
for(LL j=1;j<cnt && su[j]*i<N;j++)
{
LL to = su[j] * i;
if(i % su[j]) ans[to] = ans[i] * 2;
else if(i % (su[j]*su[j])) ans[to] = ans[i/su[j]];
else ans[to] = 0;
isprime[to] = 0;
if(i % su[j] == 0) break;
}
}
for(int i=2;i<N;i++) ans[i] += ans[i-1];
}
int main()
{
prime();
int T, n;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
printf("%lld\n", ans[n]);
}
return 0;
}