51Nod 2026 Gcd and Lcm

题目传送门
分析:
开始玩一个小小的trick
我们发现\(f(n)=\sum_{d|n}\mu(d)\cdot d\)是一个积性函数
所以:

\(~~~~f(n)=\prod f(p_i^{a_i})\)
\(~~~~f(gcd(x,y))\cdot f(lcm(x,y))=\prod f(p_i^{min(a_i,b_i)})\cdot f(p_i^{max(a_i,b_i)})\)

可以疯狂使用交换律然后。。。

\(~~~~\prod f(p_i^{min(a_i,b_i)})\cdot f(p_i^{max(a_i,b_i)})=f(x)\cdot f(y)\)

接下来就好办了,大力推:

\(~~~~\sum_{i=1}^{n}\sum_{j=1}^{n}f(gcd(i,j))\cdot f(lcm(i,j))\)
\(=\sum_{i=1}^{n}\sum_{j=1}^{n}f(i)\cdot f(j)\)
\(=(\sum_{i=1}^{n}f(i))^2\)

我们求里面的:

\(~~~~\sum_{i=1}^{n}\sum_{d|i}\mu(d)\cdot d\)
\(=\sum_{d=1}^{n}\mu(d)\cdot d\cdot \lfloor\frac{n}{d}\rfloor\)

分块处理\(\lfloor\frac{n}{d}\rfloor\)
后面的老套路,卷一个\(Id\)

\(~~~~\sum_{i=1}^{n}\sum_{d|i}\mu(d)\cdot d\cdot \frac{i}{d}=\sum_{i=1}^{n}i\sum_{d|i}\mu(d)=1\)
\(=\sum_{d=1}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)\cdot i\)

\(d=1\)提出来:

\(~~~~\sum_{i=1}^{n}\mu(i)\cdot i=1-\sum_{d=2}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)\cdot i\)$
\(~~~~S(n)=1-\sum_{d=2}^{n}d\cdot S(\lfloor\frac{n}{d}\rfloor)\)

然后杜教筛就好了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#include<string>

#define maxn 100005
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define inv2 500000004

using namespace std;

inline long long getint()
{
    long long num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

long long N;
long long pri[maxn],cnt,np[maxn],mu[maxn];
long long ans;
map<long long,long long>M;

inline void init()
{
    mu[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(!np[i])pri[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&i*pri[j]<maxn;j++)
        {
            np[i*pri[j]]=1;
            if(i%pri[j]==0)break;
            mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<maxn;i++)(mu[i]*=i)%=MOD;
    for(int i=1;i<maxn;i++)(mu[i]+=mu[i-1])%=MOD;
}

inline long long getans(long long x)
{
    if(x<maxn)return mu[x];
    if(M.count(x))return M[x];
    long long num=1;
    for(long long i=2,j;i<=x;i=j+1)
    {
        j=x/(x/i);
        (num+=MOD-(i+j)*(j-i+1)%MOD*inv2%MOD*getans(x/i))%=MOD;
    }
    return M[x]=num;
}

int main()
{
    N=getint();
    init();
    for(long long i=1,j;i<=N;i=j+1)
    {
        j=N/(N/i);
        (ans+=(N/i)*(getans(j)-getans(i-1)))%=MOD;
    }
    printf("%lld\n",(ans*ans%MOD+MOD)%MOD);
}

猜你喜欢

转载自www.cnblogs.com/Darknesses/p/12194006.html
今日推荐