CodeForces - 235E Number Challenge(莫比烏斯反演 + 數論分塊)

CodeForces - 235E Number Challenge


在這裏插入圖片描述在這裏插入圖片描述

大致題意

計算如下式子
在這裏插入圖片描述

做法

如果只是兩個數字乘積的約數個數,那麼有公式:
σ(ij)=aibj[(a,b)=1] \sigma(ij)=\sum_{a|i} \sum_{b|j}[(a,b)=1]
當有三個數字的時候,我們同樣大膽猜測然後打表驗證,可以得到如下公式:
σ(ijk)=ΣaiΣbjΣck[(a,b)=1][(a,c)=1][(b,c)=1] \sigma(ijk)=\Sigma_{a|i} \Sigma_{b|j}\Sigma_{c|k}[(a,b)=1][(a,c)=1][(b,c)=1]
那麼本題就相當於計算
Σi=1aΣj=1bΣk=1c ΣxiΣyjΣzk[(x,y)=1][(x,z)=1][(y,z)=1] \Sigma_{i=1}^{a}\Sigma_{j=1}^{b}\Sigma_{k=1}^{c}\ \Sigma_{x|i} \Sigma_{y|j}\Sigma_{z|k}[(x,y)=1][(x,z)=1][(y,z)=1]
考慮交換求和次序,先枚舉x、y和z,然後三個相互互質可以等價於其中兩個互質,第三個數字與前兩個數字的乘積互質,於是可以轉化爲如下式子:
Σx=1aΣy=1b axby[(x,y)=1] Σz=1c cz[(xy,z)=1] \Sigma_{x=1}^{a}\Sigma_{y=1}^{b}\ \lfloor\frac{a}{x}\rfloor\lfloor\frac{b}{y}\rfloor [(x,y)=1]\ \Sigma_{z=1}^{c}\ \lfloor\frac{c}{z}\rfloor[(xy,z)=1]
我們令f(n,m)=Σi=1m mi[(n,i)=1]f(n,m)=\Sigma_{i=1}^{m}\ \lfloor\frac{m}{i}\rfloor[(n,i)=1],顯然這個是可以反演的,反演之後有:
f(n,m)=Σdnm μ(d)Σi=1m/dmdi f(n,m)=\Sigma_{d|n}^{m}\ \mu(d) \Sigma_{i=1}^{\lfloor m/d \rfloor}\lfloor \frac{\lfloor\frac{m}{d}\rfloor}{i}\rfloor
g(n)=Σi=1nnig(n)= \Sigma_{i=1}^{n}\lfloor \frac{n}{i}\rfloor,這個可以用數論分塊在O(N)O(\sqrt{N})的時間複雜度內求出來。

那麼f(n,m)=Σdnm μ(d)g(md)f(n,m)=\Sigma_{d|n}^{m}\ \mu(d)g(\lfloor\frac{m}{d}\rfloor)可以在O(M)O(M)的時間複雜度內求出來。

進而對於所有的f(xy,z)f(xy,z),我們可以在O(N2)O(N^2)的時間複雜度內預處理出來。

這樣,最後的答案就是:
Σx=1aΣy=1b axby[(x,y)=1] f(xy,z) \Sigma_{x=1}^{a}\Sigma_{y=1}^{b}\ \lfloor\frac{a}{x}\rfloor\lfloor\frac{b}{y}\rfloor [(x,y)=1]\ f(xy,z)
直接枚舉i和j,判斷gcd(i,j)gcd(i,j)即可。總的時間複雜度爲O(N2logN)O(N^2\log N)。具體見代碼。

代碼

#include<bits/stdc++.h>
#define fi first
#define se second
#define LL long long
#define pb push_back
#define INF 0x3f3f3f3f
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;

const int N = 2010;
const int mod = 1 << 30;
const int msk = mod - 1;

int a,b,c,n,tot,p[N*N],mu[N*N],f[N],s[N*N];
bool isp[N*N];

void init(int N)
{
    int sz=0;
    mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!isp[i])p[++sz]=i,mu[i]=-1;
         for(int j=1;j<=sz&&(LL)i*p[j]<N;j++)
         {
            isp[i*p[j]]=1;
            if(i%p[j]==0)
            {
                mu[p[j]*i]=0; break;
            } else mu[p[j]*i]=-mu[i];
        }
    }
}


int main()
{
    sccc(a,b,c);
    init(a*b);
    for (int d=1;d<=c;d++)
    {
        int n=c/d;
        for (int l=1,r;l<=n;l=r+1)
        {
            r=n/(n/l);
            f[d]=(f[d]+(n/l)*(r-l+1))&msk;
        }
    }
    for (int i=1;i<=c;i++)
    {
        if (!mu[i]) continue;
        int w=mu[i]*f[i]; w+=w<0?mod:0;
        for (int j=i;j<=a*b;j+=i) s[j]=(s[j]+w)&msk;
    }
    int ans=0;
    for (int i=1;i<=a;i++)
        for (int j=1;j<=b;j++)
            if (__gcd(i,j)==1) ans=(ans+(LL)(a/i)*(b/j)*s[i*j]&msk)&msk;
    printf("%d",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章