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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章