题解 UVA11426 【拿行李(极限版) GCD - Extreme (II)】

原题地址UVA11426 拿行李(极限版) GCD - Extreme (II)

前置芝士:莫比乌斯反演,欧几里得算法

同类题目:UVA11417 GCD

只要你会用for循环,你就能过的题

P1390 公约数的和

SP3871 GCDEX - GCD Extreme

UVA11424 GCD - Extreme (I)

P2398 GCD SUM

纯水经验刷题数目的题,此题过后其他均可通过

正文:

\[\sum_{i=1}^{n}\sum_{j=i+1}^{n}\gcd(i,j) \]

你会发现在计算j时重复计算了i的那么我们考虑先将其看作单独的i,j,随后将重复部分减去即可

\(\begin{aligned}\sum_{i = 1}^n\sum_{j = 1}^n\gcd(i, j)= \sum_{d = 1}^nd\sum_{i = 1}^n\sum_{j = 1}^n[\gcd(i, j) = d]\end{aligned}\)

到了这里,我们发现对于\([gcd(i,j)=1]\)我们可以根据莫比乌斯函数的定义\(\begin{aligned}\sum_{d\mid n}\mu(d)\ =[n=1]\end{aligned}\)来进行替换,即\(\begin{aligned}\sum_{d=1}^n\sum_{i=1}^\frac{n}{d}\sum_{j=1}^\frac{n}{d}\sum_{p\mid i,j}\mu(p)\end{aligned}\)

我们可以按照套路将\(p\)提前\(\begin{aligned}\sum_{d=1}^n\sum_{p=1}^\frac{n}{d}\mu(p)\sum_{i=1}^\frac{n}{d}[p\mid i]\sum_{j=1}^\frac{n}{d}[p\mid j]\end{aligned}\)

对于后面的i,j两个和我们进行整除分块来做\(\begin{aligned}\sum_{d = 1}^nd\sum_{p=1}^{\left\lfloor\frac n d\right\rfloor}\mu(p)\left\lfloor\frac n {dp}\right\rfloor\left\lfloor\frac n {dp}\right\rfloor\end{aligned}\)

这里运用一个dp化Q的技巧可以变为\(\begin{aligned}\sum_{Q = 1}^n\sum_{d|Q}d*\mu(\frac Q{d})\left\lfloor\frac n {Q}\right\rfloor^2\end{aligned}\)

然后你会发现我们化简到的\(\begin{aligned}\sum_{d|Q}d*\mu(\frac Q{d})\end{aligned}\)符合\(id*\mu=\varphi\)的形式,所以我们可以进一步简化为\(\begin{aligned}\sum_{Q = 1}^n\varphi(Q)\left\lfloor\frac n {Q}\right\rfloor^2\end{aligned}\),对于询问T次值,总下来复杂度为\(O(n +T\sqrt n)\),可以通过此题,上面那个阉割版的柿子一模一样,照着用代码实现即可,此题最后还要处理一下重复情况

常见卷积

\(σ(n)\):约数和函数,表示n的全部约数和

\(\mu*id_0=\epsilon\)

\(\varphi*id_0=id_1\)

\(\mu*id_1=\varphi\)

\(id_0*id_1=σ\)

\(Code\)

#include<bits/stdc++.h>

#define LL long long

using namespace std;

template <typename T> void read(T & t) {              
    t = 0;int f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')f =- 1;ch = getchar();}
    do{t = t * 10 + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');t *= f;
}

const int kato = 4e6 + 1;

bool ispri[kato];

LL n;

LL prime[kato] , phi[kato] , sum[kato] , cnt;

inline void get_phi(){
	for(int i = 2;i <= kato;i ++){
		if(!ispri[i]){
			prime[++ cnt] = i;
			phi[i] = i - 1;
		}
		for(int j = 1;j <= cnt && (i * prime[j] <= kato);j ++){
			ispri[i * prime[j]] = 1;
			if(i % prime[j] == 0){
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			else{
				phi[i * prime[j]] = phi[i] * phi[prime[j]]; 
			}
		}
	}
	for(int i = 1;i <= kato;i ++){
//		if(i<=10) cerr<<phi[i]<<"\n";
		sum[i] = sum[i - 1] + phi[i];
	}
}

inline int Ame_(){
	phi[1] = 1 , ispri[1] = 1;
	get_phi();
	while(cin >> n){
		if(!n){
			return 0;
		}
		LL ans = 0;
		for(LL l = 1 , r;l <= n;l = r + 1){
                        r = n / (n / l);
			ans += (sum[r] - sum[l - 1]) * (n / l) * (n / l);
		}
		ans -= n * (n + 1) / 2;
		ans /= 2;
		printf("%lld\n" , ans);
	}
	return 0;
}

int Ame__ = Ame_();

signed main(){;}

注意

不知道为什么n不开long long被卡精度卡了半天没过,最后改了才没事,其他的就没什么注意的点了

posted @ 2020-07-15 11:45  Ame_sora  阅读(113)  评论(0编辑  收藏  举报