[luogu P1829] [国家集训队]Crash的数字表格 / JZPTAB

我丢 : https://www.luogu.com.cn/problem/P1829
先 假 设 n < m 先假设n < m n<m
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 n i × j gcd ⁡ ( i , j ) = ∑ d = 1 n ∑ i = 1 ⌊ n / d ⌋ ∑ j = 1 ⌊ m / d ⌋ [ gcd ⁡ ( i , j ) = 1 ] d × i × j ( 枚 举 d = g c d ) = ∑ d = 1 n ∑ i = 1 ⌊ n / d ⌋ ∑ j = 1 ⌊ m / d ⌋ ∑ k ∣ gcd ⁡ ( i , j ) μ ( k ) × d × i × j = ∑ d = 1 n ∑ k = 1 ⌊ n / d ⌋ ∑ i = 1 ⌊ n / k d ⌋ ∑ j = 1 ⌊ m / k d ⌋ μ ( k ) × d × i k × j k = ∑ T = 1 n T × ∑ i = 1 ⌊ n / T ⌋ i × ∑ j = 1 ⌊ m / T ⌋ j × ∑ k ∣ T μ ( k ) × k ( 设 T = k d , k ∗ k ∗ d = T ∗ k ) \begin{aligned} & \sum_{i=1}^n\sum_{j=1}^m lcm(i,j)\\ =& \sum_{i=1}^n\sum_{j=1}^n \frac{i \times j}{\gcd(i,j)} \\ =& \sum_{d=1}^n\sum_{i=1}^{\lfloor n/d \rfloor}\sum_{j=1}^{\lfloor m/d \rfloor}[\gcd(i,j)=1]d\times i \times j (枚举d=gcd)\\ =& \sum_{d=1}^n\sum_{i=1}^{\lfloor n/d \rfloor}\sum_{j=1}^{\lfloor m/d \rfloor}\sum_{k|\gcd(i,j)}\mu(k) \times d\times i \times j \\ =& \sum_{d=1}^n\sum_{k=1}^{\lfloor n/d\rfloor}\sum_{i=1}^{\lfloor n/kd\rfloor}\sum_{j=1}^{\lfloor m/kd\rfloor}\mu(k)\times d \times ik \times jk \\ =& \sum_{T=1}^{n}T\times\sum_{i=1}^{\lfloor n/T \rfloor}i\times\sum_{j=1}^{\lfloor m/T \rfloor}j\times\sum_{k|T}\mu(k)\times k(设T=kd,k*k*d=T*k) \end{aligned} =====i=1nj=1mlcm(i,j)i=1nj=1ngcd(i,j)i×jd=1ni=1n/dj=1m/d[gcd(i,j)=1]d×i×j(d=gcd)d=1ni=1n/dj=1m/dkgcd(i,j)μ(k)×d×i×jd=1nk=1n/di=1n/kdj=1m/kdμ(k)×d×ik×jkT=1nT×i=1n/Ti×j=1m/Tj×kTμ(k)×k(T=kd,kkd=Tk)

显 然 ∑ i = 1 ⌊ n / T ⌋ i 和 ∑ k ∣ T μ ( k ) × k 都 是 可 以 预 处 理 的 \large 显然\sum\limits_{i=1}^{\lfloor n/T \rfloor}i 和\sum_{k|T}\mu(k)\times k都是可以预处理的 i=1n/TikTμ(k)×k
时 间 复 杂 度 貌 似 是 O ( n   l n   n ) , 理 论 上 最 慢 要 跑 1.6 s , 然 鹅 常 数 不 允 许 , 还 是 T l e 了 时间复杂度貌似是 O(n \ ln\ n),理论上最慢要跑1.6s,然鹅常数不允许,还是Tle了 O(n ln n)1.6sTle
code:

#include<bits/stdc++.h>
#define N 10000005
#define mod 20101009
#define int long long
using namespace std;
int prime[N], vis[N], mu[N], s[N], sz;
void init() {
	mu[1] = 1;
	for(int i = 2; i < N; i ++) {
		if(!vis[i]) {
			prime[++ sz] = i;
			mu[i] = mod - 1;
		}
		for(int j = 1; j <= sz && prime[j] * i < N; j ++) {
			vis[prime[j] * i] = 1;
			if(i % prime[j] == 0) break;
			else mu[i * prime[j]] = mod - mu[i];
		}
	}	
	for(int i = 1; i < N; i ++)
		for(int j = i; j < N; j += i)
			s[j] = (s[j] + mu[i] * i % mod) % mod;
}
int calc(int x) {
	return (x * (x + 1) / 2) % mod;
}
int n, m;
signed main() {
	init();
	scanf("%lld%lld", &n, &m);
	int ans = 0;
	for(int T = 1; T < N; T ++) {
		int ha = 0;
		ans += T * calc(n / T) % mod * calc(m / T) % mod * s[T] % mod, ans %= mod;
	}
	printf("%lld", ans);	
	return 0;
}

主要是倍数那里好像优化不了了,那就换一种方法推吧,枚举倍数
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ d = 1 n ∑ k = 1 ⌊ n / d ⌋ ∑ i = 1 ⌊ n / k d ⌋ ∑ j = 1 ⌊ m / k d ⌋ μ ( k ) × d × i k × j k = ∑ d = 1 n d ∑ k = 1 ⌊ n / d ⌋ k 2 μ ( k ) ∑ i = 1 ⌊ n / k d ⌋ i ∑ j = 1 ⌊ m / k d ⌋ j \begin{aligned} & \sum_{i=1}^n\sum_{j=1}^m lcm(i,j)\\ =& \sum_{d=1}^n\sum_{k=1}^{\lfloor n/d\rfloor}\sum_{i=1}^{\lfloor n/kd\rfloor}\sum_{j=1}^{\lfloor m/kd\rfloor}\mu(k)\times d \times ik \times jk \\ =& \sum_{d=1}^nd\sum_{k=1}^{\lfloor n/d\rfloor}k^2\mu(k)\sum_{i=1}^{\lfloor n/kd\rfloor}i\sum_{j=1}^{\lfloor m/kd\rfloor}j\\ \end{aligned} ==i=1nj=1mlcm(i,j)d=1nk=1n/di=1n/kdj=1m/kdμ(k)×d×ik×jkd=1ndk=1n/dk2μ(k)i=1n/kdij=1m/kdj
这 个 东 西 ∑ k = 1 ⌊ n / d ⌋ k 2 μ ( k ) ∑ i = 1 ⌊ n / k d ⌋ i ∑ j = 1 ⌊ m / k d ⌋ j 看 起 来 很 整 除 分 块 \large 这个东西\sum\limits_{k=1}^{\lfloor n/d\rfloor}k^2\mu(k)\sum\limits_{i=1}^{\lfloor n/kd\rfloor}i\sum\limits_{j=1}^{\lfloor m/kd\rfloor}j\\ 看起来很整除分块 西k=1n/dk2μ(k)i=1n/kdij=1m/kdj
设 g ( n , m ) = ∑ i = 1 n i ∑ j = 1 m j , 这 个 显 然 可 以 O ( 1 ) 算 \large设g(n,m)=\sum\limits_{i=1}^{ n}i\sum\limits_{j=1}^{m}j,这个显然可以O(1)算 g(n,m)=i=1nij=1mj,O(1)
即 ∑ k = 1 ⌊ n / d ⌋ k 2 μ ( k ) ∑ i = 1 ⌊ n / k d ⌋ i ∑ j = 1 ⌊ m / k d ⌋ = ∑ k = 1 ⌊ n / d ⌋ k 2 μ ( k ) g ( ⌊ n / d k ⌋ , ⌊ m / d k ⌋ ) 显 然 可 以 整 除 分 块 即\large \sum\limits_{k=1}^{\lfloor n/d\rfloor}k^2\mu(k)\sum\limits_{i=1}^{\lfloor n/kd\rfloor}i\sum\limits_{j=1}^{\lfloor m/kd\rfloor}\\=\sum\limits_{k=1}^{\lfloor n/d\rfloor}k^2\mu(k)g(\lfloor n/dk\rfloor,\lfloor m/dk\rfloor)显然可以整除分块 k=1n/dk2μ(k)i=1n/kdij=1m/kd=k=1n/dk2μ(k)g(n/dk,m/dk)

再 设 f ( n , m ) = ∑ k = 1 n k 2 μ ( k ) g ( ⌊ n / k ⌋ , ⌊ m / k ⌋ ) \large 再设f(n, m)=\sum\limits_{k=1}^{n}k^2\mu(k)g(\lfloor n/k\rfloor,\lfloor m/k\rfloor) f(n,m)=k=1nk2μ(k)g(n/k,m/k)
那 么 ∑ d = 1 n d ∑ k = 1 ⌊ n / d ⌋ k 2 μ ( k ) ∑ i = 1 ⌊ n / k d ⌋ i ∑ j = 1 ⌊ m / k d ⌋ j      = ∑ d = 1 n d × f ( ⌊ n / d ⌋ , ⌊ m / d ⌋ ) \large 那么\sum\limits_{d=1}^nd\sum\limits_{k=1}^{\lfloor n/d\rfloor}k^2\mu(k)\sum\limits_{i=1}^{\lfloor n/kd\rfloor}i\sum\limits_{j=1}^{\lfloor m/kd\rfloor}j\\ \ \ \ \ =\sum\limits_{d=1}^nd\times f(\lfloor n/d \rfloor, \lfloor m/d \rfloor) d=1ndk=1n/dk2μ(k)i=1n/kdij=1m/kdj    =d=1nd×f(n/d,m/d)

就 是 两 个 乘 除 分 块 套 在 一 起 时 间 复 杂 度 O ( n 2 ) = O ( n ) 就是两个乘除分块套在一起时间复杂度 O( \sqrt n^2)=O(n) O(n 2)=O(n)
禁止套娃

code:

#include<bits/stdc++.h>
#define N 10000005
#define mod 20101009
#define int long long
using namespace std;
int prime[N], vis[N], mu[N], s[N], sz;
inline void init() {
	mu[1] = 1;
	for(int i = 2; i < N; i ++) {
		if(!vis[i]) {
			prime[++ sz] = i;
			mu[i] = mod - 1;
		}
		for(register int j = 1; j <= sz && prime[j] * i < N; j ++) {
			vis[prime[j] * i] = 1;
			if(i % prime[j] == 0) break;
			else mu[i * prime[j]] = mod - mu[i];
		}
	}	
	for(int i = 1; i < N; i ++) s[i] = (s[i - 1] + i * i % mod * mu[i]) % mod; 
}
int g(int x, int y) {
	return (x * (x + 1) / 2 % mod) * (y * (y + 1) / 2 % mod) % mod;
}
int f(int x, int y) {
	int ret = 0;
	for(int l = 1, r = 0; l <= x; l = r + 1) {
		r = min(x / (x / l), y / (y / l));
		ret += (s[r] - s[l - 1] + mod) * g(x / l, y / l) % mod, ret %= mod;
	}
	return ret;
}
int n, m;
signed main() {
	init();
	scanf("%lld%lld", &n, &m);
	if(n > m) swap(n, m);
	int ans = 0;
	for(int l = 1, r = 0; l <= n; l = r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += (r - l + 1) * (l + r) / 2 % mod * f(n / l, m / l) % mod, ans %= mod;
	}
	printf("%lld", ans);	
	return 0;
}

posted @ 2020-05-11 16:30  lahlah  阅读(23)  评论(0编辑  收藏  举报