HDU 5663 Hillan and the girl(莫比烏斯反演+分塊求和)
大致題意:給你兩個數字n和m,讓你求,其中f(i,j)表示gcd(i,j)是否為完全平方數,如果是則f(i,j)==0,否則為f(i,j)==1。
首先,有了之前 BZOJ 2301 的經驗,這道題目可以比較簡單的講。BZOJ 2301 這題是求一定範圍內的兩個數字gcd為1的組數。這題我直接在那個的基礎上面講。
根據之前莫比烏斯反演的結果:
到這道題的話,最後結果就是:
考慮交換求和次序:
到目前為止,我們這個式子即使用上分塊求和優化,它的的複雜度是的,注意到本題N可以到1e7這大,然後T也有1e4這麼多組,因此到這一步是遠遠不夠的。對於右邊這個求和式子,我們考慮它的性質。我們不妨令
當d為質數的時候,要滿足x^2|d只有當x為1的時候,因此此時T(d)=(d)。
當d%p!=0的時候,這個p表示某一個質數。此時我們可以考慮利用莫比烏斯函式的積性:
當d%p==0的時候。表明d已經可以被p分解,那麼d*p一定可以被p分解兩次以上,因此T(d*p)的x的取值會比T(d)多一個p*p,那麼有: ,注意到右邊的和式的x取值不會到p,那麼意味著也能被p分解兩次,即對應分解質因數p的指數大於1。根據莫比烏斯函式的定義,只要(x)種出現一個質因子的指數大於1,那麼(x)=0。因此右邊那一項等於0。
由此我麼們可以寫出T(d)的表示式:
經過整理,我們發現,T本身就可以看作莫比烏斯函式的變種,因此我可以直接用T自己的表示式:
這樣我們就可以在預處理的時候,仿照線性篩素數和莫比烏斯函式的方法,O(N)的求出T(d)。然後再對這個T(d)進行求和,仿照BZOJ 2301 的方法進行分塊求和優化,這樣詢問一次的複雜度就是。總的時間複雜度就是。具體見程式碼:
#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; }