原来……莫比乌斯反演是这么用的啊……(虽然仍然不是很明白)
首先,题目所求如下$$sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=prim]$$
我们设$f(d)$表示$gcd(i,j)=d$的$(i,j)$的对数,$g(d)$表示存在公因数为$d$的$(i,j)$的对数
那么就有$$f(d)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d]$$
$$g(d)=sum_{d|k}f(k)=lfloorfrac{N}{d} floorlfloorfrac{M}{d} floor$$
那么根据莫比乌斯反演定理,则有$$f(n)=sum_{nmid d}mu(frac{d}{n})g(d)$$
然后就可以化简了$$ans=sum_{pin prim}sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=p]$$
将$f(p)$代入,得$$ans=sum_{pin prim}f(p)$$
$$ans=sum_{pin prim}sum_{pmid d}mu(frac{d}{p})g(d)$$
我们考虑换一个枚举项,不枚举$p$,枚举$frac{d}{p}$
$$ans=sum_{pin prim}sum_{d=1}^{min(lfloorfrac{n}{p} floor,lfloorfrac{m}{p} floor)}mu(d)g(dp)\=sum_{pin prim}sum_{d=1}^{min(lfloorfrac{n}{p} floor,lfloorfrac{m}{p} floor)}mu(d)lfloorfrac{n}{dp} floorlfloorfrac{m}{dp} floor$$
然后我们把$dp$给换成$T$
$$ans=sum_{T=1}^{min(n,m)}sum_{t|T,tin prim}mu(lfloorfrac{T}{t} floor)lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor$$
$$ans=sum_{T=1}^{min(n,m)}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor(sum_{t|T,tin prim}mu(lfloorfrac{T}{t} floor))$$
然后对$(sum_{tmid T,tin prim}mu(frac{T}{t}))$求一个前缀和,就好了
这数学公式真的是打的我心力憔悴……
1 //minamoto 2 #include<cstdio> 3 #define ll long long 4 //#define min(a,b) ((a)<(b)?(a):(b)) 5 inline int min(int a,int b){return a<b?a:b;} 6 const int N=1e7+5; 7 int vis[N],mu[N],p[N],g[N],m;ll sum[N],ans; 8 void init(int n){ 9 mu[1]=1; 10 for(int i=2;i<=n;++i){ 11 if(!vis[i]) p[++m]=i,mu[i]=-1; 12 for(int j=1;j<=m&&p[j]*i<=n;++j){ 13 vis[i*p[j]]=1; 14 if(i%p[j]==0) break; 15 mu[i*p[j]]=-mu[i]; 16 } 17 } 18 for(int j=1;j<=m;++j) 19 for(int i=1;i*p[j]<=n;++i) 20 g[i*p[j]]+=mu[i]; 21 for(int i=1;i<=n;++i) 22 sum[i]=sum[i-1]+g[i]; 23 } 24 int main(){ 25 // freopen("testdata.in","r",stdin); 26 init(1e7); 27 int T;scanf("%d",&T); 28 while(T--){ 29 int n,m; 30 scanf("%d%d",&n,&m); 31 if(n>m) n^=m^=n^=m; 32 ans=0; 33 for(int l=1,r;l<=n;l=r+1){ 34 r=min(n/(n/l),m/(m/l)); 35 ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]); 36 } 37 printf("%lld ",ans); 38 } 39 return 0; 40 }