SP26108 Trending GCD

Luogu 链接
SPOJ 链接
Virtual Judge 链接

题意

题目描述

已知 \(n\)\(m\)\(1\le n,m\le10^6\)),求

\[\sum_{i=1}^n\sum_{j=1}^mij\times\gcd(i,j)\times\mu^2(\gcd(i,j)) \]

由于答案可能非常大,你只需输出其对 \(10^9+7\) 取模取模后的结果。


输入格式

多测,第一行一个正整数 \(T\)\(T\le10^3\)),代表组数。
对于每组数据,一行两个正整数 \(n\)\(m\),含意见题目描述


输出格式

题目描述

思路

不妨设 \(n\le m\),则有:

\[\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^mij\times\gcd(i,j)\times\mu^2(\gcd(i,j))\\ =&\sum_{d=1}^nd^3\mu^2(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij[\gcd(i,j)=1]\\ =&\sum_{d=1}^nd^3\mu^2(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij\sum_{k\mid i,k\mid j}\mu(k)\\ =&\sum_{d=1}^nd^3\mu^2(d)\sum_{t=1}^{\lfloor\frac{n}{d}\rfloor}t^2\mu(t)\sum_{i=1}^{\lfloor\frac{n}{td}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{td}\rfloor}ij\\ =&\sum_{T=1}^nT^2\sum_{d\mid T}d\mu^2(d)\mu(\dfrac{T}{d})\sum_{i=1}^{\lfloor\frac{n}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{T}\rfloor}ij\\ =&\sum_{T=1}^nT^2S(\lfloor\dfrac{n}{T}\rfloor)S(\lfloor\dfrac{m}{T}\rfloor)\sum_{d\mid T}d\mu^2(d)\mu(\dfrac{T}{d})\\ =&\sum_{T=1}^nT^2f(T)S(\lfloor\dfrac{n}{T}\rfloor)S(\lfloor\dfrac{m}{T}\rfloor) \end{aligned}\]

其中 \(S(n)=\displaystyle\sum_{i=1}^ni=\dfrac{n(n+1)}{2},f(n)=\displaystyle\sum_{d\mid n}d\mu^2(d)\mu(\dfrac{n}{d})\)

先预处理用线性筛筛出 \(f(n)\),并处理出 \(n^2f(n)\) 的前缀和,再用数论分块求解即可。

至于怎么用线性筛筛像 \(f(n)\) 这种一般的积性函数,请看我的这篇博客

记得取模。

程序

AC 记录

#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<iomanip>
#include<string>
#include<stack>
#define ll long long
#define ull unsigned long long
#define ld long double
#define INF 0x3f3f3f3f
#define ls rt<<1
#define rs rt<<1|1
#define lb(x) ((x)&(-(x)))
#define pb push_back
using namespace std;
const ll N=1e6+10,mod=1e9+7;
//#define use_file
#define more_test
#define need_init
#ifdef more_test
int T;
#endif

ll cnt,P[N],f[N],g[N];bool np[N];
void init(ll n=N-10){
	cnt=0;
	np[0]=np[1]=true;
	f[1]=g[1]=1;
	for(ll x_=2;x_<=n;++x_){
		if(!np[x_]){
			++cnt;
			P[cnt]=x_;
			f[x_]=x_-1;
			g[x_]=x_;
		}
		for(ll i=1;i<=cnt&&P[i]*x_<=n;++i){
			ll x=P[i]*x_;
			np[x]=true;
			if(x_%P[i]==0){
				g[x]=g[x_]*P[i];
				if(g[x]==x){
					if(g[x]==P[i]*P[i])f[x]=-P[i];
					else f[x]=0;
				}
				else f[x]=f[g[x]]*f[x/g[x]];
				break;
			}
			g[x]=P[i],f[x]=f[P[i]]*f[x_];
		}
	}
	for(ll x=1;x<=n;++x)f[x]=((f[x-1]+x*x%mod*f[x]%mod)%mod+mod)%mod;
}

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

ll n,m;

ll ans;

void SOLVE(/*int test_id*/){
	scanf("%lld%lld",&n,&m);
	ans=0;
	if(n>m)swap(n,m);
	for(ll 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*((S(n/l)*S(m/l))%mod)%mod)%mod)%mod;
	}
	printf("%lld\n",ans);
}
/*
Input:

Output:

*/
int main(){
	#ifdef use_file
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	#endif
	#ifdef need_init
	init();
	#endif
	#ifdef more_test
	scanf("%d",&T);
	for(int i=1;i<=T;++i)SOLVE(/*i*/);
	#else
	SOLVE();
	#endif
	return 0;
}
posted @ 2025-04-01 20:46  LXcjh4998  阅读(7)  评论(0)    收藏  举报