(x=p_1^{alpha_1}p_2^{alpha_2}...p_c^{alpha_c})
(f(x)=max(alpha_1,alpha_2,...,alpha_c))
(assume nleq m)
(sum_{i=1}^{n}sum_{j=1}^{m}f(gcd(i,j)))
(sum_{x=1}^{n}f(x)sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)=x])
(sum_{x=1}^{n}f(x)sum_{i=1}^{frac nx}sum_{j=1}^{frac mx}[gcd(i,j)=1])
(sum_{x=1}^{n}f(x)sum_{d=1}^{frac nx}mu(d)sum_{i=1}^{frac nx}sum_{j=1}^{frac mx}[d|i,d|j])
(sum_{x=1}^{n}f(x)sum_{d=1}^{frac nx}mu(d)lfloor frac {n}{dx} floorlfloor frac {m}{dx} floor)
(sum_{x=1}^{n}f(x)sum_{x|d}mu(frac dx)lfloor frac {n}{d} floorlfloor frac {m}{d} floor)
(sum_{d=1}^{n}lfloor frac {n}{d} floorlfloor frac {m}{d} floorsum_{x|d}f(x)mu(frac dx))
根据套路,我们到了这个式子。直接暴力调和级数算 (sum_{x|d}f(x)mu(frac dx)) 的前缀和,时间复杂度 (O(nlog n))
怎么 (O(n)) 筛的锅待填
(O(nlog n):)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=10000000+10;
int n,m,f[maxn],mu[maxn],prim[maxn],vis[maxn],cnt;
ll g[maxn];
inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
void pre(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){prim[++cnt]=i;mu[i]=-1;}
for(int j=1;i*prim[j]<=n&&j<=cnt;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0) break;
mu[i*prim[j]]=-mu[i];
}
}
int num,ans;
for(int i=1;i<=cnt;i++){
for(int j=prim[i];j<=n;j+=prim[i]){
num=j;ans=0;
while(num%prim[i]==0) num/=prim[i],ans++;
f[j]=max(f[j],ans);
}
}
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=i) g[j]+=f[i]*mu[j/i];
for(int i=1;i<=n;i++) g[i]+=g[i-1];
}
int main()
{
pre(10000000);
int T=read();
while(T--){
n=read(),m=read();
if(n>m) swap(n,m);
ll ans=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(ll)(n/l)*(m/l)*(g[r]-g[l-1]);
}
printf("%lld
",ans);
}
return 0;
}
(O(n):)
#include <bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
const int maxn=10000000+10;
int n,m,f[maxn],low[maxn],prim[maxn],vis[maxn],cnt;
ll g[maxn];
inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
void pre(int n){
for(int i=2;i<=n;i++){
if(!vis[i]){low[i]=prim[++cnt]=i;f[i]=g[i]=1;}
for(int j=1;i*prim[j]<=n&&j<=cnt;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0){
f[i*prim[j]]=f[i]+1;low[i*prim[j]]=low[i]*prim[j];
if(i==low[i]) g[i*prim[j]]=1;
else g[i*prim[j]]=(f[i/low[i]]==f[i*prim[j]])?-g[i/low[i]]:0;
break;
}
f[i*prim[j]]=1;low[i*prim[j]]=prim[j];
g[i*prim[j]]=(f[i]==1)?-g[i]:0;
}
}
for(int i=1;i<=n;i++) g[i]+=g[i-1];
}
signed main()
{
pre(10000000);
int T=read();
while(T--){
n=read(),m=read();
if(n>m) swap(n,m);
ll ans=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(ll)(n/l)*(m/l)*(g[r]-g[l-1]);
}
printf("%lld
",ans);
}
return 0;
}