D、brz的函数
(
sum_{i=1}^nsum_{j=1}^nmu(ij)=sum_{i=1}^nsum_{j=1}^nmu(i)mu(j)[gcd(i,j)=1]=sum_{i=1}^nsum_{j=1}^nmu(i)mu(j)sum_{d|gcd(i,j)}mu(d)=sum_{i=1}^nsum_{j=1}^nmu(i)mu(j)sum_{d|i,j}mu(d)=sum_{d=1}^nmu(d)sum_{d|i}mu(i)sum_{d|j}mu(j)=sum_{d=1}^nmu(d)left(sum_{d|i}mu(i)
ight)^2
)
将公式化简如上,发现该式子只需要求出两部分(mu)函数以及(sum_{d|i}mu(i))(某个因子(d)倍数的(mu)函数和),发现无法在T循环内求出,只能预先处理,定义两个新变量数组mu_fac_sum和ans.mu_fac_sum[i]表示因子i倍数的(mu)之和;ans[i]表示n==i时原式答案,我们预先处理每一个n,发现n-1的值会对n的值有所贡献,以及n的因子中增值的贡献,时间复杂度(O(nlogn+n^{frac{3}{2}}))
#include <bits/stdc++.h>
using namespace std;
const int NMAX = 5e4 + 2;
typedef long long ll;
ll mu[NMAX],mu_fac_sum[NMAX],ans[NMAX];
int prime[NMAX],isw[NMAX],tot;
void init()
{
mu[1] = 1;
for(int i = 2; i < NMAX; i++)
{
if( !isw[i] )
{
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot; j++)
{
if(i * prime[j] >= NMAX) break;
isw[i * prime[j]] = true;
if( i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
ans[1] = 1;
mu_fac_sum[1] = 1;
for(int i = 2;i < NMAX;i++)
{
ans[i] = ans[i - 1];
for(int j = 1;j * j <= i;j++)
{
if(i % j == 0)
{
ans[i] += mu[j]*(mu[i]*mu[i]+2*mu[i]*mu_fac_sum[j]);
mu_fac_sum[j] += mu[i];
if(j * j != i)
{
ans[i] += mu[i/j]*(mu[i]*mu[i]+2*mu[i]*mu_fac_sum[i/j]);
mu_fac_sum[i/j] += mu[i];
}
}
}
}
}
int main()
{
int t, n;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%lld
",ans[n]);
}
return 0;
}