CF1717E Madoka and The Best University 题解

\(\text{Preface}\)

思路来自 \(\text{gtm1514}\),所以就不交洛谷题解了,但本着我竟然会推这个玩意的神奇,所以写一发。

这里\(\text{gtm1514}\) 大佬的题解,同步发表于洛谷。

洛谷题目链接


\[\sum_{a+b+c = n} { \text{lcm}(c, \gcd(a, b)) } \]

看到 \(gcd\) 首先给拆出来枚举。

\[\sum_{d=1}^{n} { \sum_{a+b+c = n} { \text{lcm}(c, d)[\gcd(a, b)=d] } } \]

考虑化简 \([\gcd(a, b)]\)

根据辗转相除法,有 \(\gcd(x, y) = \gcd(y, x-y)\)

那么代入到 \(\gcd(a, b) = d\) 中即为:

\[\gcd(a, a+b) = d \]

再将 \(d\) 除过去得到:

\[\gcd(\frac {a} {d}, \frac {a+b} {d}) = 1 \]

由于 \(a+b+c = n\) 所以直接把 \(a+b\) 给换成 \(n-c\)

\[\gcd(\frac {a} {d}, \frac {n-c} {d}) = 1 \]

\(\gcd(\frac {a} {d}, \frac {n-c} {d}) = 1\) 时才对答案有贡献,于是发现这玩意就是个 \(\varphi(\frac {n-c} {d})\)

此时整个柿子变为:

\[\sum_{d=1}^{n} { \sum_{a+b+c = n} { lcm(c, d) \cdot \varphi(\frac {n-c} {d}) [d | n-c] } } \]

因为 \(d | n-c\),即 \(n-c\)\(d\) 的倍数,那么就可以枚举这个倍数 \(bs\) 得到 \(n-c = d \cdot bs\),解出来 $ = n - d \cdot bs$,于是就可以算了。

枚举倍数和求 \(\gcd\) 都是 \(O(\log n)\) 的,所以总时间复杂度 \(O(n \log^2 n)\)

注意这个题 \(\varphi(1) = 0\)。我也不清楚为什么。。

code
#include <iostream>
#define GMY (520&1314)
#define char_phi signed
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define re register int
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
#define P 1000000007
#define mod %
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}

/*
	我竟然会了
*/

long long n, final_ans;

char nop[N];
long long prime[N], phi[N];

inline void Getphi(){
	phi[1] = 0;
	
	for (long long i = 2 ; i <= n ; ++ i){
		if (nop[i] == false)
			prime[++ prime[0]] = i, phi[i] = i-1;
		for (long long j = 1 ; j <= prime[0] ; ++ j){
			if (i * prime[j] > n)
				break;
			nop[i*prime[j]] = true;
			if (i % prime[j] == 0)
				phi[i*prime[j]] = phi[i] * prime[j];
			else 
				phi[i*prime[j]] = phi[i] * (prime[j]-1);
		}
	}
}

long long gcd(long long x, long long y) {return ((y == 0) ? (x) : (gcd(y, x%y)));}
inline long long lcm(long long x, long long y) {return (x * y / gcd(x, y));}

inline void work(){
	cin >> n;
	
	Getphi();
	
	for (long long d = 1, c ; d <= n ; ++ d){
		// 枚举倍数
		for (long long bs = 1 ; d*bs <= n ; ++ bs){
			c = n - d * bs;
			final_ans = (final_ans + lcm(c, d) * phi[bs] mod P) mod P;
		}
	}
	
	cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a, a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

再次鸣谢 \(\text{gtm1514}\) 大佬!

posted @ 2022-10-13 11:51  char_phi  阅读(43)  评论(0)    收藏  举报