洛谷 P1829 :[国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

洛谷 P1829 :[国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)_第1张图片


题解:
假设 n < m n < m n<m,一波化简: ∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 m i ∗ j g c d ( i , j ) = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 m i ∗ j d ∗ [ g c d ( i , j ) = d ] = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ g c d ( i , j ) = 1 ] \sum_{i = 1}^n\sum_{j = 1}^{m}lcm(i,j) = \sum_{i = 1}^n\sum_{j = 1}^{m}\frac{i * j}{gcd(i,j)} = \sum_{d = 1}^{n}\sum_{i = 1}^n\sum_{j = 1}^{m}\frac{i * j}{d}*[gcd(i,j) = d] =\sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m} {d}\rfloor} i * j * d*[gcd(i,j) = 1] i=1nj=1mlcm(i,j)=i=1nj=1mgcd(i,j)ij=d=1ni=1nj=1mdij[gcd(i,j)=d]=d=1ni=1dnj=1dmijd[gcd(i,j)=1]
设 : f ( d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ g c d ( i , j ) = d ] 设:f(d) = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor} i * j * d*[gcd(i,j) = d] f(d)=d=1ni=1dnj=1dmijd[gcd(i,j)=d]
令 F ( x ) = ∑ x ∣ d f ( d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ x ∣ g c d ( i , j ) ] = ∑ d = 1 n ∑ i = 1 ⌊ n x ∗ d ⌋ ∑ j = 1 ⌊ m x ∗ d ⌋ i ∗ j ∗ d ∗ x 2 令F(x) = \sum_{x | d} f(d) = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor} i * j * d*[x | gcd(i,j)] = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{x * d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{x * d}\rfloor} i * j * d * x ^2 F(x)=xdf(d)=d=1ni=1dnj=1dmijd[xgcd(i,j)]=d=1ni=1xdnj=1xdmijdx2
反 演 一 下 : f ( d ) = ∑ d ∣ x μ ( x d ) ∗ F ( x ) 反演一下:f(d) = \sum_{d | x} \mu(\frac{x}{d}) * F(x) f(d)=dxμ(dx)F(x)
f ( 1 ) = ∑ x = 1 ⌊ n d ⌋ μ ( x d ) ∗ F ( x ) = ∑ d = 1 n d ∗ ∑ x = 1 ⌊ n d ⌋ x 2 ∗ μ ( x ) ∗ ∑ i = 1 ⌊ n d ∗ x ⌋ i ∑ j = 1 ⌊ m d ∗ x ⌋ j f(1) = \sum_{x = 1}^{\lfloor\frac{n}{d}\rfloor} \mu(\frac{x}{d}) * F(x)=\sum_{d = 1}^nd*\sum_{x = 1}^{\lfloor\frac{n}{d}\rfloor}x^2*\mu(x)*\sum_{i = 1}^{\lfloor\frac{n}{d * x}\rfloor}i\sum_{j = 1}^{\lfloor\frac{m}{d * x}\rfloor}j f(1)=x=1dnμ(dx)F(x)=d=1ndx=1dnx2μ(x)i=1dxnij=1dxmj
到这一步已经可以两层分块 O ( n ) O(n) O(n)过掉这题 (准确来说是 O ( n 3 4 O(n^{\frac{3}{4}} O(n43)?)
这里为什么 x x x 的上界是 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor dn:因为前面设了 f ( d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ g c d ( i , j ) = d ] f(d) = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor} i * j * d*[gcd(i,j) = d] f(d)=d=1ni=1dnj=1dmijd[gcd(i,j)=d]
x x x是d的倍数,由于 i 上限是 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor dn(这里假设 n < m n < m n<m),因此d的倍数最大到 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor dn(准确的说是gcd(i,j)最大到 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor dn), x x x 应该枚举到 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor dn
注意到最终式子里枚举了 d , x d,x d,x,产生了 d ∗ x d * x dx,可以令 T = d ∗ x d * x dx,枚举 T 和 d,然后可以线性筛优化一下,解决多组的情况。

注意第一层分块的时候右边界取 m i n ( m / ( m / i ) , n / ( n / i ) ) min(m / (m / i),n / (n / i)) min(m/(m/i),n/(n/i)),因为后面有一个 ⌊ ⌊ m d ⌋ x ⌋ \lfloor\frac{\lfloor\frac{m}{d}\rfloor}{x}\rfloor xdm


代码:

#include
using namespace std;
const int mod = 20101009;
const int maxn = 1e7 + 10;
bool ispri[maxn];
int pri[maxn],mu[maxn];
typedef long long ll;
ll sum[maxn];
int n,m;
void sieve(int n) {
	ispri[0] = ispri[1] = true;
	pri[0] = 0;mu[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!ispri[i]) pri[++pri[0]] = i,mu[i] = -1;
		for(int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
			ispri[i * pri[j]] = true;
			if(i % pri[j] == 0) {
				mu[i * pri[j]] = 0;
				break;
			}
			mu[i * pri[j]] = -mu[i];
		}
	}
	sum[0] = 0;
	for(int i = 1; i <= n; i++)
		sum[i] = (sum[i - 1] + mu[i] * 1ll * i % mod * i % mod + mod) % mod;
}
ll cal(int n) {
	return 1ll * (1 + n) * n / 2 % mod;
}
int main() {
	sieve(10000000);
	scanf("%d%d",&n,&m);
	int l1,r1,l2,r2;
	ll res = 0;
	if(n > m) swap(n,m);
	for(l1 = 1; l1 <= n; l1 = r1 + 1) {
		r1 = min(n / (n / l1),m / (m / l1));
		ll tmp = 0;
		for(l2 = 1; l2 <= n / l1; l2 = r2 + 1) {
			int p1 = n / l1,p2 = m / l1;
			r2 = min(p1 / (p1 / l2),p2 / (p2 / l2));
			tmp = (tmp + cal(p1 / l2) * cal(p2 / l2) % mod * ((sum[r2] - sum[l2 - 1] + mod) % mod) % mod) % mod;
		}
		res = (res + 1ll * (l1 + r1) * (r1 - l1 + 1) / 2 % mod * tmp % mod + mod) % mod;
	}	
	printf("%lld\n",res);
	return 0;
} 

你可能感兴趣的:(莫比乌斯反演,数论,莫比乌斯反演,数论)