DZY Loves Math

\(x=p_1^{\alpha_1}p_2^{\alpha_2}...p_c^{\alpha_c}\)

\(f(x)=\max(\alpha_1,\alpha_2,...,\alpha_c)\)

\(assume\ n\leq 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}\rfloor\lfloor \frac {m}{dx}\rfloor\)

\(\sum_{x=1}^{n}f(x)\sum_{x|d}\mu(\frac dx)\lfloor \frac {n}{d}\rfloor\lfloor \frac {m}{d}\rfloor\)

\(\sum_{d=1}^{n}\lfloor \frac {n}{d}\rfloor\lfloor \frac {m}{d}\rfloor\sum_{x|d}f(x)\mu(\frac dx)\)

根据套路,我们到了这个式子。直接暴力调和级数算 \(\sum_{x|d}f(x)\mu(\frac dx)\) 的前缀和,时间复杂度 \(O(n\log n)\)

怎么 \(O(n)\) 筛的锅待填

\(O(n\log 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\n",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\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/owencodeisking/p/10237229.html