UESTC618:无完全平方因子数
题意:
给定一个(n),求区间([1,n])中的无平方因子数的个数。
比如说20就是一个有平方因子数,因为(20=2^2 imes 5)。
思路:
对于一个数,根据算术基本定理,一定可以拆成若干个整数相乘的形式,记为(x=p_1^{c_1},...,p_n^{c_n})的形式。
-
那么当一个数字的(c_igeq 2)的时候,这个数字一定是有平方因子数。
-
如果所有的(c_i)都是(1),那么这个数字一定是无平方因子数。
那么答案就是莫比乌斯函数的平方和。
[S(n) = sum_{i=1}^n mu^2(i)
]
虽然这里看起来很明显的需要杜教筛,但是我找不出合适的(g)函数来卷,可能有方法,但我不知道。
考虑一个数(p),那么(p^2)的倍数都有平方因子,这样的数字有(frac{n}{p^2})个,应该从答案中去除。
但是对于两个素数(p_1,p_2)而言,(p_1^2p_2^2)的倍数会被去掉两次,所以应该加回来,这里显然是容斥原理,而且莫比乌斯函数恰好为系数。
假设说(d)是几个不同的素数的乘积,那么他们对答案的贡献一定是:
[mu(d)frac{n}{d^2}
]
所以说答案改写为了:
[sum_{i=1}^nmu^2=sum_{d=1}^{sqrt{n}}mu(d)frac{n}{d^2}
]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6;
bool vis[maxn+10];
int primes[maxn+10], cnt, mu[maxn+10];
void init(int n)
{
mu[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!vis[i])
{
primes[++cnt] = i;
mu[i] = -1;
}
for(int j = 1; primes[j] <= n/i; j++)
{
vis[primes[j]*i] = 1;
if(i % primes[j] == 0) break;
else mu[i*primes[j]] = -mu[i];
}
}
}
ll n;
void solve()
{
cin >> n; ll res = 0;
for(ll i = 1; i <= n/i; i++)
res += 1ll*mu[i]*n/(i*i);
cout << res << endl;
}
int main()
{
init(maxn);
int T; scanf("%d", &T);
while(T--) solve();
return 0;
}