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 dcdot lfloorfrac{n}{d} floor)

分块处理(lfloorfrac{n}{d} floor)
后面的老套路,卷一个(Id)

(~~~~sum_{i=1}^{n}sum_{d|i}mu(d)cdot dcdot frac{i}{d}=sum_{i=1}^{n}isum_{d|i}mu(d)=1)
(=sum_{d=1}^{n}dsum_{i=1}^{lfloorfrac{n}{d} floor}mu(i)cdot i)

(d=1)提出来:

(~~~~sum_{i=1}^{n}mu(i)cdot i=1-sum_{d=2}^{n}dsum_{i=1}^{lfloorfrac{n}{d} floor}mu(i)cdot i)
(~~~~S(n)=1-sum_{d=2}^{n}dcdot S(lfloorfrac{n}{d} floor))

然后杜教筛就好了

#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
",(ans*ans%MOD+MOD)%MOD);
}

原文地址:https://www.cnblogs.com/Darknesses/p/12194006.html