D、brz的函数(牛客练习赛72)
D、brz的函数
\(
\sum_{i=1}^n\sum_{j=1}^n\mu(ij)=\sum_{i=1}^n\sum_{j=1}^n\mu(i)\mu(j)[gcd(i,j)=1]=\sum_{i=1}^n\sum_{j=1}^n\mu(i)\mu(j)\sum_{d|gcd(i,j)}\mu(d)=\sum_{i=1}^n\sum_{j=1}^n\mu(i)\mu(j)\sum_{d|i,j}\mu(d)=\sum_{d=1}^n\mu(d)\sum_{d|i}\mu(i)\sum_{d|j}\mu(j)=\sum_{d=1}^n\mu(d)\left(\sum_{d|i}\mu(i)\right)^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\n",ans[n]);
}
return 0;
}