[BZOJ3309]DZY Loves Math(莫比烏斯反演+線性篩)
阿新 • • 發佈:2019-01-18
質因子 不存在 pan init swap i++ () 包含 love
$\sum\limits_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum\limits_{d|T}f(d)\mu(\frac{T}{d})$
求出$g(n)=\sum_{d|T}f(d)\mu(\frac{n}{d})$的前綴和,分塊加速。
考慮怎麽快速求g。觀察什麽時候d能對答案產生貢獻,顯然當且僅當:對於n的每個質因子,d包含這個質因子的次冪數至多比n包含這個質因子的次冪數少1,否則n/d就會包含平方因子。
接下來分兩種情況考慮(顯然若n只包含一個質因子則g(n)=1):
1) n中存在兩個質因子次數不同。
那麽考慮所有次數的最大值,設為k。當我們確定n中次數為k的那些因子的選取情況時(這裏選取是指是否d包含這個因子的次數比n少1),剩下的數若選取個數為奇數則$\mu$為-1否則為1。考慮到組合數的性質,n個數中選取奇數個的方案數與選取偶數個相同,所以這種情況整個的貢獻為0。
2) n中所有質因子次數相同
與上面不同的是,這裏已經不存在次數小於k的因子了。那麽,這些質因子的選取情況與$\mu$的乘積同樣由於上面那個組合數的性質,使和為0。但有一個數不同,就是當d包含的所有因子的次數都比n少1時,f(d)為k-1而不是k。綜上這部分的g(n)=(-1)^(質因子個數+1)。
考慮線性篩求g。分別記錄每個數最小因子的次數,最小因子的乘積,轉移顯然。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=10000010; 8 int T,n,m,tot,b[N],p[N]; 9 ll g[N],f[N],h[N]; 10 11 void init(int n){ 12 rep(i,2,n){ 13 if(!b[i]) p[++tot]=i,h[i]=1,f[i]=i,g[i]=1; 14 for (int j=1; j<=tot && p[j]*i<=n; j++){ 15 int t=p[j]*i; b[t]=1; 16 if (i%p[j]==0){ 17 h[t]=h[i]+1; f[t]=f[i]*p[j]; 18 int s=t/f[t]; 19 if (s==1) g[t]=1; else g[t]=(h[s]==h[t]) ? -g[s] : 0; 20 }else h[t]=1,f[t]=p[j],g[t]=(h[i]==1) ? -g[i] : 0; 21 } 22 } 23 rep(i,1,n) g[i]+=g[i-1]; 24 } 25 26 ll solve(){ 27 if (n>m) swap(n,m); ll res=0; 28 for (int i=1,lst; i<=n; i=lst+1) 29 lst=min(n/(n/i),m/(m/i)),res+=1ll*(n/i)*(m/i)*(g[lst]-g[i-1]); 30 return res; 31 } 32 33 int main(){ 34 freopen("bzoj3309.in","r",stdin); 35 freopen("bzoj3309.out","w",stdout); 36 init(10000000); 37 for (scanf("%d",&T); T--; ) 38 scanf("%d%d",&n,&m),printf("%lld\n",solve()); 39 return 0; 40 }
[BZOJ3309]DZY Loves Math(莫比烏斯反演+線性篩)