1. 程式人生 > >HDU 5663 Hillan and the girl(莫比烏斯反演+分塊求和)

HDU 5663 Hillan and the girl(莫比烏斯反演+分塊求和)

大致題意:給你兩個數字n和m,讓你求\sum_{i=1}^{n}\sum_{j=1}^{m}f(i,j),其中f(i,j)表示gcd(i,j)是否為完全平方數,如果是則f(i,j)==0,否則為f(i,j)==1。

首先,有了之前 BZOJ 2301 的經驗,這道題目可以比較簡單的講。BZOJ 2301 這題是求一定範圍內的兩個數字gcd為1的組數。這題我直接在那個的基礎上面講。

根據之前莫比烏斯反演的結果:

           \large F(i)=\sum_{i|d}f(d)=>f(i)=\sum_{i|d}\mu(\frac{d}{i})F(d)=\sum_{i|d}\mu(\frac{d}{i})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor

到這道題的話,最後結果就是:\large ans=n*m-\sum_{x^2}^{min(n,m)}\sum_{x^2|d}^{min(n,m)}\mu(\frac{d}{x^2})*\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor

考慮交換求和次序:                  \large ans=n*m-\sum_{d=1}^{min(n,m)}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor*\sum_{x^2|d}^{min(n,m)}\mu(\frac{d}{x^2})

到目前為止,我們這個式子即使用上分塊求和優化,它的的複雜度是O(TN\sqrt{N})的,注意到本題N可以到1e7這大,然後T也有1e4這麼多組,因此到這一步是遠遠不夠的。對於右邊這個求和式子,我們考慮它的性質。我們不妨令T(d)=\sum_{x^2|d}\mu(\frac{d}{x^2})

。分情況考慮:

當d為質數的時候,要滿足x^2|d只有當x為1的時候,因此此時T(d)=\mu(d)。

當d%p!=0的時候,這個p表示某一個質數。此時我們可以考慮利用莫比烏斯函式的積性:

                          \large T(d*p)=\sum_{x^2|d}\mu(\frac{d*p}{x^2})=\mu(p)*\sum_{x^2|d}\mu(\frac{d}{x^2})=\mu(p)*T(d)

當d%p==0的時候。表明d已經可以被p分解,那麼d*p一定可以被p分解兩次以上,因此T(d*p)的x的取值會比T(d)多一個p*p,那麼有:  T(d*p)=\mu(\frac{d*p}{p*p})+\sum_{x^2|d}\mu(\frac{d*p}{x^2}),注意到右邊的和式的x取值不會到p,那麼意味著\frac{d*p}{x^2}也能被p分解兩次,即對應分解質因數p的指數大於1。根據莫比烏斯函式的定義,只要\mu(x)種出現一個質因子的指數大於1,那麼\mu(x)=0。因此右邊那一項等於0。

由此我麼們可以寫出T(d)的表示式: 

                   

經過整理,我們發現,T本身就可以看作莫比烏斯函式的變種,因此我可以直接用T自己的表示式:

                               \large T(d*p)\begin{cases}T(p) & d = 1 \\ T(p)*T(j) & d\%p!=0 \\ T(\frac{d}{p}) & d\%p==0 \end{cases}

這樣我們就可以在預處理的時候,仿照線性篩素數和莫比烏斯函式的方法,O(N)的求出T(d)。然後再對這個T(d)進行求和,仿照BZOJ 2301 的方法進行分塊求和優化,這樣詢問一次的複雜度就是\large O(\sqrt{N})。總的時間複雜度就是\large O(T\sqrt{N})。具體見程式碼:

#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define LL long long
#define N 10000010

using namespace std;
 
int s[N],p[N],T[N];
bool isp[N];
 
void init()
{
    int sz=0;
    s[1]=T[1]=1; 
    for(int i=2;i<N;i++)
    {
        if(!isp[i]) p[++sz]=i,T[i]=-1;
        for(int j=1;j<=sz&&i*p[j]<N;j++)
        {
            isp[i*p[j]]=1;
            if(i%p[j]==0)
            {
                T[p[j]*i]=T[i/p[j]];
                break;
            } else T[p[j]*i]=-T[i];
        }
        s[i]=s[i-1]+T[i];
    }
}
 
LL cal(int n,int m)
{
    LL res=0,last;
    for(int i=1;i<=n&&i<=m;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        res+=1LL*(s[last]-s[i-1])*(n/i)*(m/i);
    }
    return res;
}
 
int main()
{
    int b,d,n;
    IO; init(); cin>>n;
    while(n--)
    {
        cin>>b>>d;
        cout<<(LL)b*d-cal(b,d)<<endl;
    }
    return 0;
}