LCM

首先

\[\sum_{i=1}^{n}i=\dfrac{n*(n+1)}{2} \]

\[\sum_{i=1}^{n}i^2=\dfrac{n*(n+1)*(2n+1)}{6} \]

\[\sum_{i=1}^{n}i^3=(\sum_{i=1}^{n}i)^2 \]

P3911 最小公倍数之和

\[\sum_{i=1}^{n}\sum_{j=1}^{n}lcm(A_i,A_j) \]

观察值域,发现与 \(n\) 同阶,记 \(c_i\) 表示数字 i 出现次数。

\[\sum_{i=1}^{n}\sum_{j=1}^{n}lcm(i,j)*c_i*c_j \]

\[\sum_{i=1}^{n}\sum_{j=1}^{n}\dfrac{i*j}{(i,j)}*c_i*c_j \]

\[\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{n}\dfrac{i*j}{d}*c_i*c_j*[(i,j)=d] \]

\[\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}i*j*c_{id}*c_{jd}*[(i,j)=1] \]

\[\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}i*j*c_{id}*c_{jd}*\sum_{k|(i,j)}\mu(k) \]

\[\sum_{d=1}^{n}d\sum_{k=1}^{\frac{n}{d}}\mu(k)*k^2*\sum_{i=1}^{\frac{n}{dk}}\sum_{j=1}^{\frac{n}{dk}}i*j*c_{idk}*c_{jdk} \]

\(T=dk\) 枚举 T

\[\sum_{T=1}^{n}T\sum_{k|T}\mu(k)*k*(\sum_{i=1}^{\frac{n}{T}}c_{iT}*i)^2 \]

因为枚举 dk,而 k 是必须枚举的,所以可以省略掉 d。然后原来有 \(\sum_{d=1}^{n}d\),可以从后面找个 k 组成 T。

考虑枚举的是 \(T=dk\),所以一定有 \(k|T\).

最后预处理出 \(\sum_{k|T}\mu(k)*k\),暴力做\((\sum_{i=1}^{\frac{n}{T}}c_{iT}*i)^2\).

因为 \(\sum_{i=1}^{n}\frac{n}{i}\) 这样子是个调和级数的形式,所以后面暴力是 \(O(n \ln n)\)的。

\(\text{Code}\)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>

#define N (int)(5e4+5)
#define int long long

using namespace std;

bool vis[N];
int pri[N],mu[N],sum[N],cnt;
int n,a[N],c[N];

int rd() {
	int f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)) {
		sum=(sum<<3)+(sum<<1)+ch-'0';
		ch=getchar();
	}
	return sum*f;
}

void pr(int x) {
	if(x<0) {
		putchar('-');
		x=-x;
	}
	if(x>9) pr(x/10);
	putchar(x%10+'0');
}

void get_mu() {
	mu[1]=1;
	for(int i=2;i<=N-5;i++) {
		if(!vis[i]) {
			mu[i]=-1;
			pri[++cnt]=i;
		}
		for(int j=1;j<=cnt&&pri[j]*i<=N-5;j++) {
			vis[pri[j]*i]=1;
			if(i%pri[j]==0) break;
			mu[pri[j]*i]=-mu[i];
		}
	}
}


signed main() {
	get_mu();
	n=rd(); int qwq=0;
	for(int i=1;i<=n;i++) {
		a[i]=rd(); qwq=max(qwq,a[i]);
		++c[a[i]];
	}
	for(int i=1;i<=qwq;i++)
		for(int j=i;j<=qwq;j+=i)
			sum[j]+=mu[i]*i;
	int ans=0;
	for(int T=1;T<=qwq;T++) {
		int ret=0;
		for(int i=1;i<=qwq/T;i++) ret+=i*c[i*T];
		ret*=ret;
		ans+=T*ret*sum[T];
		//cout<<ret<<endl;
	}
	pr(ans);
	return 0;
}

较为困难的LCM

\[\sum_{i=1}^{n}\sum_{j=1}^{n}lcm(i,j) \]

\[n \le 10^{10} \]

那么我们没办法用 \(O(n \ln n)\) 的办法了。

先化简下

\[\sum_{i=1}^{n}\sum_{j=1}^{n}\dfrac{i*j}{(i,j)} \]

\[\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{n}\dfrac{i*j}{d}*[(i,j)=d] \]

\[\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}i*j*[(i,j)=1] \]

\[h(n)=\sum_{i=1}^{n}i*[(i,n)=1] \]

这个东西就等于(实际上是我 oeis 出来的)

\[\dfrac{n*\phi(n)+[n=1]}{2} \]

考虑证明下

已有 \(gcd(i,n)=1\).

若有一个数 \(d,(d\neq1)\) 使得 \(gcd(n,(n-i))=d.\)

那么 \(n\%d=0,(n-i)\%d=0\implies i\%d=0\)

那么 \(gcd(i,n)=d\).

所以可得,已有 \(gcd(i,n)=1 \implies gcd(n,(n-i))=1.\)

考虑 \(i,n-i\) 成对出现,且对答案贡献是 \(n\).

则去重后答案为 \(\dfrac{n*\phi(n)+[n=1]}{2}\).

那么

\[ans=\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}i*j*[(i,j)=1] \]

\[\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}i*2*h(i)-1 \]

\[\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}i*2*\dfrac{i*\phi(i)+[i=1]}{2}-1 \]

\[\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}i^2*\phi(i) \]

因为 \([i=1]\)\(-1\) 抵消了。

\[S(n)=\sum_{i=1}^{n}i^2*\phi(i) \]

那么

\[ans=\sum_{d=1}^{n}d*S(\frac{n}{d}) \]

\[f(x)=x^2*\phi(x),g(x)=x^2. \]

那么

\[(f*g)(n)=\sum_{d|n}f(d)g(\frac{n}{d})=n^3 \]

这里省略的可以在这里找到

接下来就是杜教筛了。

最后整个 \(ans\) 来个整除分块。

\(\text{Code}\)

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>

#define N (int)(1.6e6)
#define ll long long
#define mod 1000000007

using namespace std;
ll lrd() {
    ll f=1,sum=0; char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return sum*f;
}

bool vis[N];
int pri[N>>2],tot=0;
ll phi[N],inv6;
map<ll,ll>ans_phi;

ll fpow(ll x,ll y=mod-2) {
	ll res=1;
	while(y) {
		if(y&1) res=res*x%mod;
		x=x*x%mod; y>>=1;
	}
	return res;
}

void init() {
	phi[1]=1;
	for(int i=2;i<N;i++) {
		if(!vis[i]) pri[++tot]=i,phi[i]=i-1;
		for(int j=1;j<=tot&&pri[j]*i<N;j++) {
			vis[pri[j]*i]=1;
			if(i%pri[j]==0) {
				phi[i*pri[j]]=phi[i]*pri[j];
				break;
			}
			phi[i*pri[j]]=phi[i]*phi[pri[j]];
		}
	}
	for(int i=1;i<N;i++) phi[i]=(phi[i-1]+phi[i]*i%mod*i%mod)%mod;
} 

ll SUM1(ll x) {
	x%=mod;
	return (x*(x+1)/2)%mod;
}

ll SUM2(ll x) {
	x%=mod;
	return x*(x+1)%mod*(2*x+1)%mod*inv6%mod;
}

ll SUM3(ll x) {
	return SUM1(x)*SUM1(x)%mod;
}

ll get_phi(ll x) {
	if(x<N) return phi[x];
	if(ans_phi[x]) return ans_phi[x];
	ll ans=SUM3(x);
	for(ll l=2,r;l<=x;l=r+1) {
		r=x/(x/l);
		ans-=(SUM2(r)-SUM2(l-1))*get_phi(x/l)%mod;
		ans%=mod;
	}  
	return ans_phi[x]=ans;
}

int main() {
	init();
	ll n; n=lrd(); inv6=fpow(6);
	ll ans=0;
	for(ll l=1,r;l<=n;l=r+1) {
		r=n/(n/l);
		ans+=(SUM1(r)-SUM1(l-1))*get_phi(n/l)%mod;
		ans%=mod;
	}
	ans=(ans%mod+mod)%mod;
	printf("%lld",ans);
	return 0;
}
posted @ 2022-02-08 17:53  FxorG  阅读(236)  评论(0编辑  收藏  举报