洛谷P1829 [国家集训队]Crash的数字表格 / JZPTAB(包括多组数据)

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

加强版:题面不变,包含多组数据,数据组数为 T T T 1 ≤ T ≤ 1 0 4 1\leq T\leq 10^4 1T104

题目大意

给出 n , m n,m n,m,求 ∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum\limits_{i=1}^n\sum\limits_{j=1}^m lcm(i,j) i=1nj=1mlcm(i,j)。有 T T T组数据, 1 ≤ T ≤ 1 0 4 1\leq T\leq 10^4 1T104

题解

前置知识:莫比乌斯反演

不妨设 n ≤ m n\leq m nm

题意即求

∑ i = 1 n ∑ j = 1 m i × j gcd ⁡ ( i , j ) \sum\limits_{i=1}^n\sum\limits_{j=1}^m \dfrac{i\times j}{\gcd(i,j)} i=1nj=1mgcd(i,j)i×j

枚举 gcd ⁡ \gcd gcd

∑ d = 1 n ∑ i = 1 n ∑ j = 1 m i × j d [ gcd ⁡ ( i , j ) = d ] \sum\limits_{d=1}^n\sum\limits_{i=1}^n\sum\limits_{j=1}^m\dfrac{i\times j}{d}[\gcd(i,j)=d] d=1ni=1nj=1mdi×j[gcd(i,j)=d]

稍作转换可得

∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i × j × [ gcd ⁡ ( i , j ) = 1 ] \sum\limits_{d=1}^nd\sum\limits_{i=1}^{\lfloor\frac nd\rfloor}\sum\limits_{j=1}^{\lfloor\frac md\rfloor}i\times j\times[\gcd(i,j)=1] d=1ndi=1dnj=1dmi×j×[gcd(i,j)=1]

利用莫比乌斯函数的性质,可得

∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i × j ∑ k ∣ gcd ⁡ ( i , j ) μ ( t ) \sum\limits_{d=1}^nd\sum\limits_{i=1}^{\lfloor\frac nd\rfloor}\sum\limits_{j=1}^{\lfloor\frac md\rfloor}i\times j\sum\limits_{k|\gcd(i,j)}\mu(t) d=1ndi=1dnj=1dmi×jkgcd(i,j)μ(t)

枚举 k k k

∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ k 2 × μ ( k ) ∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ m k d ⌋ i × j \sum\limits_{d=1}^nd\sum\limits_{k=1}^{\lfloor\frac nd\rfloor}k^2\times \mu(k)\sum\limits_{i=1}^{\lfloor\frac{n}{kd}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{kd}\rfloor}i\times j d=1ndk=1dnk2×μ(k)i=1kdnj=1kdmi×j

∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ m k d ⌋ i × j \sum\limits_{i=1}^{\lfloor\frac{n}{kd}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{kd}\rfloor}i\times j i=1kdnj=1kdmi×j可变为 ⌊ n k d ⌋ × ( ⌊ n k d ⌋ + 1 ) 2 × ⌊ n k d ⌋ × ( ⌊ n k d ⌋ + 1 ) 2 \dfrac{\lfloor\frac{n}{kd}\rfloor\times(\lfloor\frac{n}{kd}\rfloor+1)}{2}\times \dfrac{\lfloor\frac{n}{kd}\rfloor\times (\lfloor\frac{n}{kd}\rfloor+1)}{2} 2kdn×(⌊kdn+1)×2kdn×(⌊kdn+1)。设 g t ( k ) = k × ( k + 1 ) 2 gt(k)=\dfrac{k\times (k+1)}{2} gt(k)=2k×(k+1),则原式变为

∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ k 2 × μ ( k ) × g t ( ⌊ n k d ⌋ ) × g t ( ⌊ m k d ⌋ ) \sum\limits_{d=1}^nd\sum\limits_{k=1}^{\lfloor\frac nd\rfloor}k^2\times \mu(k)\times gt(\lfloor\dfrac{n}{kd}\rfloor)\times gt(\lfloor\dfrac{m}{kd}\rfloor) d=1ndk=1dnk2×μ(k)×gt(⌊kdn⌋)×gt(⌊kdm⌋)

T = k d T=kd T=kd,枚举 T T T,可得

∑ T = 1 n g t ( ⌊ n T ⌋ ) × g t ( ⌊ m T ⌋ ) ∑ k ∣ T T k × k 2 × μ ( k ) \sum\limits_{T=1}^ngt(\lfloor\dfrac{n}{T}\rfloor)\times gt(\lfloor\dfrac{m}{T}\rfloor)\sum\limits_{k|T}\dfrac{T}{k}\times k^2\times \mu(k) T=1ngt(⌊Tn⌋)×gt(⌊Tm⌋)kTkT×k2×μ(k)

整理可得

∑ T = 1 n g t ( ⌊ n T ⌋ ) × g t ( ⌊ m T ⌋ ) × T ∑ k ∣ T k × μ ( k ) \sum\limits_{T=1}^ngt(\lfloor\dfrac{n}{T}\rfloor)\times gt(\lfloor\dfrac{m}{T}\rfloor)\times T\sum\limits_{k|T} k\times \mu(k) T=1ngt(⌊Tn⌋)×gt(⌊Tm⌋)×TkTk×μ(k)

现在的问题在于如何快速求出 ∑ k ∣ T k × μ ( k ) \sum\limits_{k|T} k\times \mu(k) kTk×μ(k)。设 f ( d ) = ∑ k ∣ d k × μ ( k ) f(d)=\sum\limits_{k|d} k\times \mu(k) f(d)=kdk×μ(k),我们发现 f ( d ) f(d) f(d)是一个积性函数,可以 O ( n ) O(n) O(n)预处理出。

g t ( k ) gt(k) gt(k) f ( d ) f(d) f(d) O ( n ) O(n) O(n)预处理出,每次询问用数论分块只需 O ( n ) O(\sqrt n) O(n ),所以总时间复杂度为 O ( n + T n ) O(n+T\sqrt n) O(n+Tn )

注:下面代码是有多组数据的,在洛谷上交时要去掉。

code

#include
using namespace std;
const int N=10000000;
const long long mod=20101009;
int t,n,m,z[N+5],p[N+5];
long long ans,f[N+5];
long long gt(int t){
	return 1ll*t*(t+1)/2%mod;
}
int main()
{
	f[1]=1;
	for(int i=2;i<=N;i++){
		if(!z[i]){
			p[++p[0]]=i;f[i]=(1-i+mod)%mod;
		}
		for(int j=1;j<=p[0]&&i*p[j]<=N;j++){
			z[i*p[j]]=1;
			if(i%p[j]==0){
				f[i*p[j]]=f[i];
				break;
			}
			f[i*p[j]]=f[i]*f[p[j]]%mod;
		}
	}
	for(int i=1;i<=N;i++){
		f[i]=(f[i-1]+i*f[i]%mod)%mod;
	}
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		ans=0;
		if(n>m) swap(n,m);
		for(int l=1,r;l<=n;l=r+1){
			r=min(n/(n/l),m/(m/l));
			ans=(ans+(f[r]-f[l-1]+mod)%mod*gt(n/l)%mod*gt(m/l)%mod)%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

你可能感兴趣的:(题解,c++)