枚举倍数的一种灵活的变形:g(d)=∑d∣inf(i)=∑i=1⌊nd⌋f(i⋅d)g(d)=\sum_{d|i}^nf(i)=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i\cdot d)g(d)=∑d∣inf(i)=∑i=1⌊dn⌋f(i⋅d)
很显然,但有时能发挥大作用。
其实本质还是要理解西格玛究竟是在算什么
解析
一个重要的前置结论:
d(i⋅j)=∑x∣i,y∣j[gcd(x,y)=1]d(i\cdot j)=\sum_{x|i,y|j}[\gcd(x,y)=1]d(i⋅j)=x∣i,y∣j∑[gcd(x,y)=1]
证明:
尝试把所有互质的数对 (x,y)(x,y)(x,y) 和 i⋅ji\cdot ji⋅j 的所有因子建立双射关系。首先,对于只有 i,ji,ji,j 一方有的质因子,直接归给有该项质因子的那一方对应的 xxx 或 yyy。对于双方都有的质因子 ppp,若 iii 的对应次数为 aaa,jjj 的对应次数为 bbb,如果 i⋅ji\cdot ji⋅j 的某个因子 ppp 的次数 ccc 满足 c≤ac\le ac≤a,就当成 xxx 含有 pcp^cpc 的因子;若 c>ac>ac>a,就当成 yyy 含有 pc−ap^{c-a}pc−a 次方的因子。这样我们就建立起了双射关系,且所有的 x,yx,yx,y 都是互质的,证毕。
我们再化一下这个 ddd 函数:
d(i,j)=∑x∣i∑y∣j[gcd(i,j)=1]=∑x∣i∑y∣j∑k∣gcd(x,y)μ(k)=∑k∣i,k∣jμ(k)∑k∣x,x∣i∑k∣y,y∣j1=∑k∣i,k∣jμ(k)∑x∣ikik∑y∣jkjk1=∑k∣i,k∣jμ(k)d(ik)d(jk)d(i,j)=\sum_{x|i}\sum_{y|j}[\gcd(i,j)=1]\\=\sum_{x|i}\sum_{y|j}\sum_{k|\gcd(x,y)}\mu(k)\\=\sum_{k|i,k|j}\mu(k)\sum_{k|x,x|i}\sum_{k|y,y|j}1\\=\sum_{k|i,k|j}\mu(k)\sum_{x|\frac{i}{k}}^{\frac{i}{k}}\sum_{y|\frac{j}{k}}^{\frac{j}{k}}1\\=\sum_{k|i,k|j}\mu(k)d(\frac{i}{k})d(\frac{j}{k})d(i,j)=x∣i∑y∣j∑[gcd(i,j)=1]=x∣i∑y∣j∑k∣gcd(x,y)∑μ(k)=k∣i,k∣j∑μ(k)k∣x,x∣i∑k∣y,y∣j∑1=k∣i,k∣j∑μ(k)x∣ki∑kiy∣kj∑kj1=k∣i,k∣j∑μ(k)d(ki)d(kj)
带回原式:
∑i=1n∑j=1md(ij)=∑i=1n∑j=1m∑k∣i,k∣jμ(k)d(ik)d(jk)=∑kμ(k)∑k∣in∑k∣jmd(ik)d(jk)=∑kμ(k)∑i=1⌊nk⌋∑j=1⌊mk⌋d(i)d(j)=∑kμ(k)(∑i=1⌊nk⌋d(i))⋅(∑j=1⌊mk⌋d(j))\sum_{i=1}^n\sum_{j=1}^md(ij)=\sum_{i=1}^n\sum_{j=1}^m\sum_{k|i,k|j}\mu(k)d(\frac{i}{k})d(\frac{j}{k})\\=\sum_{k}\mu(k)\sum_{k|i}^n\sum_{k|j}^md(\frac i k)d(\frac j k)\\=\sum_k\mu(k)\sum_{i=1}^{\lfloor\frac n k\rfloor}\sum_{j=1}^{\lfloor\frac m k\rfloor}d(i)d(j)\\=\sum_k\mu(k)(\sum_{i=1}^{\lfloor\frac n k\rfloor}d(i))\cdot(\sum_{j=1}^{\lfloor\frac m k\rfloor}d(j))i=1∑nj=1∑md(ij)=i=1∑nj=1∑mk∣i,k∣j∑μ(k)d(ki)d(kj)=k∑μ(k)k∣i∑nk∣j∑md(ki)d(kj)=k∑μ(k)i=1∑⌊kn⌋j=1∑⌊km⌋d(i)d(j)=k∑μ(k)(i=1∑⌊kn⌋d(i))⋅(j=1∑⌊km⌋d(j))
线性筛出 μ,d\mu,dμ,d,预处理出前缀和,整除分块即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=1e5+100;
int n,m;int p[N],tot,vis[N],mu[N],msum[N],d[N];
ll dsum[N];
void init(int n){mu[1]=1;d[1]=1;for(int i=2;i<=n;i++){if(!vis[i]) p[++tot]=i,mu[i]=-1,d[i]=2;for(int j=1;j<=tot&&p[j]<=n/i;j++){vis[i*p[j]]=1;if(i%p[j]==0){mu[i*p[j]]=0;d[i*p[j]]=d[i]+d[i]-d[i/p[j]];break;}mu[i*p[j]]=-mu[i];d[i*p[j]]=d[i]*2;}}for(int i=1;i<=n;i++){msum[i]=msum[i-1]+mu[i];dsum[i]=dsum[i-1]+d[i];}return;
}signed main() {
#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);
#endifinit(5e4);int T=read();while(T--){n=read();m=read();ll ans(0);for(int l=1,r;l<=min(n,m);l=r+1){r=min(n/(n/l),m/(m/l));ans+=(msum[r]-msum[l-1])*dsum[n/l]*dsum[m/l];}printf("%lld\n",ans);}return 0;
}
/*
5
5
8
1
46
3564
*/