1. 程式人生 > >【bzoj3309】DZY Loves Math 莫比烏斯反演+線性篩

【bzoj3309】DZY Loves Math 莫比烏斯反演+線性篩

例如 一行 根據 優化 long long ast 以及 -1 變化

題目描述

對於正整數x,定義f(x)為x所含質因子的最大冪指數。例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0。
給定正整數n,m,求$\sum\limits_{i=1}^n\sum\limits_{j=1}^mf(\gcd(i,j))$

輸入

第一行一個數T,表示詢問數。
接下來T行,每行兩個數n,m,表示一個詢問。

輸出

對於每一個詢問,輸出一行一個非負整數作為回答。

樣例輸入

4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957

樣例輸出

35793453939901

14225956593420
4332838845846
15400094813


題解

莫比烏斯反演+線性篩

(為了方便,以下公式默認$n\le m$)

首先有公式:

$\ \ \ \ \sum\limits_{i=1}^n\sum\limits_{j=1}^mf(\gcd(i,j))\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=d]\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^{\lfloor\frac nd\rfloor}\sum\limits_{j=1}^{\lfloor\frac md\rfloor}[\gcd(i,j)=1]\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^{\lfloor\frac nd\rfloor}\sum\limits_{j=1}^{\lfloor\frac md\rfloor}\sum\limits_{p|\gcd(i,j)}\mu(p)\\=\sum\limits_{d=1}^nf(d)\sum\limits_{p=1}^{\lfloor\frac nd\rfloor}\mu(p)\lfloor\frac n{dp}\rfloor\lfloor\frac m{dp}\rfloor$

然後令$D=dp$,可以得到:

$\ \ \ \ \sum\limits_{d=1}^nf(d)\sum\limits_{p=1}^{\lfloor\frac nd\rfloor}\mu(p)\lfloor\frac n{dp}\rfloor\lfloor\frac m{dp}\rfloor\\=\sum\limits_{D=1}^n\lfloor\frac n{D}\rfloor\lfloor\frac m{D}\rfloor\sum\limits_{p|D}\mu(p)f(\frac Dp)$

這個形式看起來非常妙,然而$n$和$m$有$10^7$之大,使用枚舉倍數的調和級數時間復雜度預處理的方法的話肯定會GG(親測就算加上$\mu\neq 0$的優化也是過不去的)。

然而經過打表可以發現,對於每個$D$,$g(D)=\sum\limits_{p|D}\mu(p)f(\frac Dp)$都是$0$、$-1$或$1$中的一個值。

至此可以猜測想出結論:$g(D)$的值只與其質因子的構成有關。

事實上,具體的結論是:當$D\neq 1$時,令$D=p_1^{a_1}p_2^{a_2}...p_k^{a_k}$,則當且僅當$a_1=a_2=...=a_k$時,$g(D)=(-1)^{k+1}$;否則$g(D)=0$。

證明

觀察$g(D)$的形式:只有當$p$中不含有平方因子時,$\mu(p)$才不為0。所以相當於:$D$的所有質因子中,每個質因子有選和不選兩種選擇,選了的話它的貢獻就會減1。

先證明$a_1$、$a_2$、...、$a_k$不全相等時,$g(D)=0$:如果所有質因子的次數不全相等,那麽考慮次數最小的那個質因子,它無論是否選擇都不會影響$f(\frac Dp)$的值,只是差在$\mu(p)$的正負。這樣選它和不選它,產生的貢獻正好正負抵消,因此$g(D)$一定是0。

再考慮$a_1=a_2=...=a_k$的情況:當且僅當每個質因子都選擇時,$f(\frac Dp)$等於$a-1$,否則等於$a$。那麽如果把$a-1$的那次貢獻看作$a$,那麽答案應該是0。所以只需要考慮把$a-1$看成$a$的變化。顯然當$k$為奇數時$\mu(p)$為負,$a-1$的貢獻為負,因此答案為$1$;否則$a-1$的貢獻為正,答案為$-1$。

所以就可以根據每個數的質因子構成來線性篩出每個數的$g$值。具體做法:如果把每個數寫成$v·p^a$的形式,那麽維護每個數的:$v$的每個質因子的次數(不全相同則為-1)、$a$的值以及質因子種類數$k$。根據這些很容易計算出當前數的$g$。註意需要考慮$v=1$的情況。

然後就可以直接求前綴和,對於每組詢問枚舉商即可。

時間復雜度$O(n+T\sqrt n)$

#include <cstdio>
#include <algorithm>
#define N 10000010
#define k 10000000
using namespace std;
int v[N] , c[N] , cnt[N] , prime[N] , tot , sum[N];
bool np[N];
int main()
{
	int i , j , T , n , m , last;
	long long ans;
	for(i = 2 ; i <= k ; i ++ )
	{
		if(!np[i]) prime[++tot] = i , c[i] = cnt[i] = 1;
		for(j = 1 ; j <= tot && i * prime[j] <= k ; j ++ )
		{
			np[i * prime[j]] = 1;
			if(i % prime[j] == 0)
			{
				v[i * prime[j]] = v[i] , c[i * prime[j]] = c[i] + 1 , cnt[i * prime[j]] = cnt[i];
				break;
			}
			else
			{
				if(!v[i] || v[i] == c[i]) v[i * prime[j]] = c[i];
				else v[i * prime[j]] = -1;
				c[i * prime[j]] = 1 , cnt[i * prime[j]] = cnt[i] + 1;
			}
		}
		if(v[i] && v[i] != c[i]) sum[i] = sum[i - 1];
		else if(cnt[i] & 1) sum[i] = sum[i - 1] + 1;
		else sum[i] = sum[i - 1] - 1;
	}
	scanf("%d" , &T);
	while(T -- )
	{
		scanf("%d%d" , &n , &m);
		ans = 0;
		for(i = 1 ; i <= n && i <= m ; i = last + 1)
			last = min(n / (n / i) , m / (m / i)) , ans += (long long)(n / i) * (m / i) * (sum[last] - sum[i - 1]);
		printf("%lld\n" , ans);
	}
	return 0;
}

【bzoj3309】DZY Loves Math 莫比烏斯反演+線性篩