题解-[国家集训队]Crash的数字表格 / JZPTAB

题解-[国家集训队]Crash的数字表格 / JZPTAB

前置知识:

莫比乌斯反演 </>


[国家集训队]Crash的数字表格 / JZPTAB

单组测试数据,给定 (n,m) ,求

[sumlimits_{i=1}^nsumlimits_{j=1}^moperatorname{lcm}(i,j)mod 20101009 ]

数据范围:(1le n,mle 10^7)


作为写出了最暴力的做法的蒟蒻,来推个式子。

(nle m),一气呵成:

[egin{split} g(n,m)=&sumlimits_{i=1}^nsumlimits_{j=1}^moperatorname{lcm}(i,j)\ =&sumlimits_{i=1}^nsumlimits_{j=1}^mfrac{ij}{gcd(i,j)}\ =&sumlimits_{d=1}^nsumlimits_{i=1}^nsumlimits_{j=1}^mfrac{ij}{d}[gcd(i,j)=d]\ =&sumlimits_{d=1}^nsumlimits_{i=1}^{lfloorfrac nd floor}sumlimits_{j=1}^{lfloorfrac md floor}ijd[gcd(i,j)=1]\ =&sumlimits_{d=1}^n dsumlimits_{i=1}^{lfloorfrac nd floor}isumlimits_{j=1}^{lfloorfrac md floor}jsumlimits_{k|gcd(i,j)}mu(k)\ =&sumlimits_{d=1}^n dsumlimits_{k=1}^nmu(k)sumlimits_{i=1}^{lfloorfrac nd floor}i[k|i]sumlimits_{j=1}^{lfloorfrac md floor}j[k|j]\ =&sumlimits_{d=1}^n dsumlimits_{k=1}^nmu(k)sumlimits_{i=1}^{lfloorfrac {n}{dk} floor}iksumlimits_{j=1}^{lfloorfrac {m}{dk} floor}jk\ =&sumlimits_{d=1}^n dsumlimits_{k=1}^nk^2mu(k)frac{lfloorfrac{n}{dk} floor(lfloorfrac{n}{dk} floor+1)}{2}cdotfrac{lfloorfrac{m}{dk} floor(lfloorfrac{m}{dk} floor+1)}{2}\ end{split} ]

(x=dk) 带入:

[g(n,m)=sumlimits_{x=1}^nxcdotfrac{lfloorfrac{n}{x} floor(lfloorfrac{n}{x} floor+1)}{2}cdotfrac{lfloorfrac{m}{x} floor(lfloorfrac{m}{x} floor+1)}{2}sumlimits_{k|x}kmu(k) ]

然后筛 (mu(k)) 时顺便计算 (h(k)=kmu(k)),最后狄利克雷前缀和求 (f(k)=sumlimits_{k|x}kmu(k))

别忘了膜拜 (20101009),时间复杂度 (Theta(N+n))

#include <bits/stdc++.h>
using namespace std;

//&Start
#define lng long long
#define lit long double
#define kk(i,n) "
 "[i<n]
const int inf=0x3f3f3f3f;
const lng Inf=1e17;

//&Mobius
const int N=1e7;
const int mod=20101009;
bitset<N+10> np;
int mu[N+10],cnt,p[N+10],f[N+10];
void Mobius(){
	f[1]=mu[1]=1;
	for(int i=2;i<=N;i++){
		if(!np[i]) p[++cnt]=i,mu[i]=-1;
		f[i]=(mu[i]*i+mod)%mod;
		for(int j=1;j<=cnt&&i*p[j]<=N;j++){
			np[i*p[j]]=1;
			if(i%p[j]==0){mu[i*p[j]]=0;break;}
			mu[i*p[j]]=-mu[i];
		}
	}
	for(int j=1;j<=cnt;j++)
		for(int i=1;i*p[j]<=N;i++)
			(f[i*p[j]]+=f[i])%=mod; //狄利克雷前缀和
}


//&Data
int n,m,ans;
int bitfun(int x){
	lng res=1ll*x*f[x]%mod;
	(res*=1ll*(n/x+1)*(n/x)/2%mod)%=mod;
	(res*=1ll*(m/x+1)*(m/x)/2%mod)%=mod; //如上
	//这个1ll不乘要爆long long,30分。
	return (int)res;
}

//&Main
int main(){
	Mobius();
	scanf("%d%d",&n,&m);
	if(n>m) swap(n,m);
	for(int i=1;i<=n;i++)
		(ans+=bitfun(i))%=mod;
	printf("%d
",ans);
	return 0;
}

祝大家学习愉快!

原文地址:https://www.cnblogs.com/George1123/p/12456965.html