2020.06.13日常總結

正文前的一些提示:打 UVA 的題時,輸出後一定要有一個空行,否則等待您的,就是一次又一次的 WA

UVA11426    GCD Extreme(II)\color{green}{\texttt{UVA11426\ \ \ \ GCD Extreme(II)}}

[Problem]\color{blue}{\texttt{[Problem]}}

  • 給定一個數 nn,求:

    i=1nj=i+1ngcd(i,j)\sum\limits_{i=1}^{n} \sum\limits_{j=i+1}^{n} \gcd(i,j)

  • 2n4×1062 \leq n \leq 4 \times 10^6,多組數據,輸入以 00 結束。保證答案在 long long 範圍內。

[Solution]\color{blue}{\texttt{[Solution]}}

fi=j=1i1gcd(j,i)f_i = \sum\limits_{j=1}^{i-1} \gcd(j,i),則答案 Si=j=2nfjS_i=\sum\limits_{j=2}^{n} f_j

求出了所有的 fi(2iN)f_i(2 \leq i \leq N) 後(N=4×106N = 4 \times 10^6),就可以用 O(N)O(N) 的時間求出所有的 Si(2iN)S_i (2 \leq i \leq N)

現在,讓我們考慮如何求出 fi(2iN)f_i(2 \leq i \leq N)

枚舉 dd,代表 gcd(j,i)=d\gcd(j,i)=d,假設這樣的 jjkk 個,則對答案的貢獻爲 k×dk \times d

接下來,考慮如何求出 kk 的值。顯然,i,ji,j 一定滿足 di,djd|i,d|j,且 id,jd\dfrac{i}{d},\dfrac{j}{d} 互質。

簡單地證明一下:顯然 i,ji,j 一定是滿足 di,djd|i,d|j 的,否則 gcd(i,j)d\gcd(i,j) \neq d。爲什麼 id,jd\dfrac{i}{d},\dfrac{j}{d} 互質呢?
考慮反證法。假設 id,jd\dfrac{i}{d},\dfrac{j}{d} 不互質,記其最大公約數爲 gg。那麼 gg 一定也是 i,ji,j 的因子,而且 d×gi,d×gjd \times g | i,d \times g | j,即 d×gd \times g 也是 i,ji,j 的公約數,這與 ddi,ji,j 的最大公約數矛盾。

有了這個定理,所以一對可行的 (i,j)(i,j) 一定與一對互質的數 (id,jd)(\dfrac{i}{d}, \dfrac{j}{d}) 一一對應。而因爲 id,jd\dfrac{i}{d},\dfrac{j}{d} 互質,所以這樣的 jd\dfrac{j}{d} 一共有 φ(id)\varphi(\dfrac{i}{d}) 個,故這樣的 jj 一共有 φ(id)\varphi(\dfrac{i}{d}) 個。

所有的 φ(i)(1iN)\varphi(i)(1 \leq i \leq N) 可以 O(N)O(N) 求出,而枚舉 dd 並計算 fi(2iN)f_i(2 \leq i \leq N)O(N×logN)O(N\times \log N) 的,求出 Si(2iN)S_i(2 \leq i \leq N)O(N)O(N) 的,輸出答案是 O(1)O(1) 的。故總的時間複雜度爲 O(N×N+T)O(N \times N + T),其中 TT 是一共的數據個數。

[code]\color{blue}{\texttt{[code]}}

const int N=4e6+100;
typedef long long ll;
int n,phi[N];ll S[N],f[N];
int prime[N],g[N],tot;//線性篩 
inline void get_prime(int N){
	tot=0;phi[1]=1;//初始化 
	for(int i=2;i<=N;i++){
		if (!g[i]){//如果i是個素數 
			phi[i]=i-1;//初始化phi值 
			g[i]=prime[++tot]=i;
		}
		for(int j=1;j<=tot;j++){
			if (1ll*i*prime[j]>N) break;//剪枝 
			register int t=i*prime[j];//updata
			phi[t]=phi[i]*(prime[j]-(prime[j]<g[i]));
			g[t]=prime[j];//記錄每個數的最小因子 
			if (prime[j]==g[i]) break;//算法優化 
		}
	}
}
int main(){
	get_prime(4e6);//求出phi值 
	for(int i=1;i<=(int)4e6;i++)
		for(int j=i*2;j<=(int)4e6;j+=i)
			f[j]+=1ll*i*phi[j/i];
	S[2]=f[2];//注意S[2]應特別賦值f[2] 
	for(int i=3;i<=(int)4e6;i++)
		S[i]=S[i-1]+f[i];//前綴和 
	while (~scanf("%d",&n)&&n)
		printf("%lld\n",S[n]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章