【莫比烏斯反演】BZOJ3309 DZY Loves Math

Description

  對於正整數n,定義f(n)爲n所含質因子的最大冪指數。例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0。
  給定正整數a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b)。T<=1e4; a,b<=1e7。spa

 

Solution

  一開始沒仔細看數據範圍而後打了一個每一個詢問O(n)的,固然T了code

  (盜一張圖)blog

  

  一開始我按照第二行的作的,裏層外層循環都和ab有關,每一層都要sqrt(n)ip

  而後發現f(d)和ab無關,因而把f放到裏面,把和ab有關的拎出來,就變成了第三行的式子get

  這樣裏面一層循環與ab無關,能夠預處理好string

  咱們要求的就是後面sigma的前綴和it

  不難想到nlogn的預處理,但這題比較卡仍是Tio

  因而要這麼作ast

  

  設g(T)=Σ[d|T]f(d)μ(T/d)class

  大力分析

  將T質因數分解,對於每個p^a,T/d的p係數要麼爲0要麼爲1,不然μ(T/d)必定爲0不考慮

  若是存在ai!=aj,關於T的因數p按a能夠分爲兩個集合,a最大A集合和a非最大的B集合

  f取值由A集合的選取決定

  μ由選取的總個數決定

  不管A怎麼選,在B中選取的奇偶方案數相同,因而總貢獻必定爲0

  也就是若是存在ai!=aj, g(T)=0

 

  那麼a都相等的狀況

  選奇數選偶數方案相同貢獻也爲0

  但若是p所有都選那麼f的貢獻爲a-1(其他選法f貢獻都爲a)

  因此要多減一個1,考慮μ的影響,對於有k個p的T,g(T)=(-1)^(k+1)

 

  具體的計算方法在線性篩的時候記錄一個當前最小素數的次數和去掉最小素數後上一個數

  若是清楚線性篩的原理那麼仍是很好想的

  預處理複雜度同線性篩,詢問複雜度爲sqrt(n)

 

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=1e7+5;
 7 
 8 bool flag[maxn]; int prime[maxn],cnt;
 9 int t[maxn],last[maxn],g[maxn];
10 int n,m;
11 
12 void getmu(){
13     for(int i=2;i<=1e7;i++){
14         if(!flag[i]){
15             prime[++cnt]=i;
16             last[i]=t[i]=1;
17             g[i]=1;
18         }
19         for(int j=1;i*prime[j]<=1e7&&j<=cnt;j++){
20             int x=i*prime[j];
21             flag[x]=1;
22             if(i%prime[j]==0){
23                 last[x]=last[i];
24                 t[x]=t[i]+1;
25                 if(last[x]==1)
26                     g[x]=1;
27                 else 
28                     g[x]=(t[last[x]]==t[x]?-g[last[x]]:0);
29                 break;
30             }
31             last[x]=i;
32             t[x]=1;
33             g[x]=(t[i]==1?-g[i]:0);
34         }
35     }
36     for(int i=1;i<=1e7;i++)
37         g[i]+=g[i-1];
38 }
39 
40 ll f(int x,int y){
41     ll ret=0;
42     for(int i=1,pos=1;i<=x;i=pos+1){
43         pos=min(x/(x/i),y/(y/i));
44         ret+=1ll*(g[pos]-g[i-1])*(x/i)*(y/i);
45     }
46     return ret;
47 }
48 
49 int main(){
50     getmu();
51     
52     int T;
53     scanf("%d",&T);
54     while(T--){
55         scanf("%d%d",&n,&m);
56         if(n>m) swap(n,m);
57         printf("%lld\n",f(n,m));
58     }
59     return 0;
60 }
相關文章
相關標籤/搜索