D、brz的函数(牛客练习赛72)

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;
}
原文地址:https://www.cnblogs.com/lemon-jade/p/13939139.html