J. Sum
A square-free integer is an integer which is indivisible by any square number except 11. For example, 6 = 2 \cdot 36=2⋅3 is square-free, but 12 = 2^2 \cdot 312=22⋅3 is not, because 2^222 is a square number. Some integers could be decomposed into product of two square-free integers, there may be more than one decomposition ways. For example, 6 = 1\cdot 6=6 \cdot 1=2\cdot 3=3\cdot 2, n=ab6=1⋅6=6⋅1=2⋅3=3⋅2,n=ab and n=ban=ba are considered different if a \not = ba̸=b. f(n)f(n) is the number of decomposition ways that n=abn=ab such that aa and bb are square-free integers. The problem is calculating \sum_{i = 1}^nf(i)∑i=1nf(i).
Input
The first line contains an integer T(T\le 20)T(T≤20), denoting the number of test cases.
For each test case, there first line has a integer n(n \le 2\cdot 10^7)n(n≤2⋅107).
Output
For each test case, print the answer \sum_{i = 1}^n f(i)∑i=1nf(i).
Hint
\sum_{i = 1}^8 f(i)=f(1)+ \cdots +f(8)∑i=18f(i)=f(1)+⋯+f(8)
=1+2+2+1+2+4+2+0=14=1+2+2+1+2+4+2+0=14.
题意:
令F(i)表示满足x*y=i,且x和y都不包含平方数因子的合法(x,y)对数,求∑F(i)
思路:
容易发现∑F(i) n > 0等价于(非质数的平凡的倍数 )相乘小于或等于n的方案。 比如对于当n = 8,等价于1,2,3,5,6,7这六个数两两相乘并且相乘结果小于8的种类的个数 ,比如1 * 1 , 1 * 2 , 1 * 3 , 1 * 5 , 1 * 6, 1 * 7 , 2 * 1 , 2 * 2 , 2 * 3 , 3 * 1 , 3 * 2 , 5 * 1 , 6 * 1 , 7 * 1 。共14种。
于是我们可以筛掉质数的平方的倍数,再求非质数的平方的倍数的前缀和(学长说时间复杂度是o(n)的),又因为1 * 2 和2 * 1 等价,所以后面可以优化下变成 O(2n + t * sqrt(n)),又因为题目的t很小,所以方法可行。
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
int ans[20000009];
bool tmp[20000009];
const int MAXN=5009;
bool flag[MAXN];
int primes[MAXN/3],pi;
void prime() {
int i,j;
pi=0;
memset(flag,false,sizeof(flag));
for(i=2; i<MAXN; i++) {
if(!flag[i]) primes[pi++]=i;
for(j=0; (j < pi) && (i*primes[j] < MAXN); j++) {
flag[i * primes[j]] = true;
if(i % primes[j]==0) break;//保证非素数只筛一次
}
}
}
int main() {
prime();
for(int i = 2;i < 5000;i++){
if(flag[i] == false){//如果他是质数,筛掉其平方的倍数
for(int j = i * i;j <= 20000000;j += i * i){
tmp[j] = true;
}
}
}
ans[0] = 0;
for(int i = 1;i < 20000009;i++){//求前缀和
ans[i] = ans[i - 1];
if(tmp[i] == false){
ans[i]++;
}
}
// for(int i = 1;i < 50;i++){
// printf("%d ",ans[i]);
// }
int t,n;
scanf("%d",&t);
while(t--){
long long answer = 0;
scanf("%d",&n);
for(int i = 1;i <= n / i;i++){
if(tmp[i] != true){
answer += (ans[n / i] - ans[i]) * 2 + 1;
}
}
printf("%lld\n",answer);
}
}