[BZOJ 3561] DZY Loves Math VI

BZOJ传送门

Description

给定正整数 n , m n,m n,m。求

img

Input

一行两个整数 n , m n,m n,m

Output

一个整数,为答案模 1000000007 1000000007 1000000007后的值。

Sample Input

5 4

Sample Output

424

HINT

数据规模:

1 ≤ n , m ≤ 500000 1\le n,m\le 500000 1n,m500000,共有3组数据。

解题分析

∑ i = 1 n ∑ j = 1 m l c m ( i , j ) g c d ( i , j ) = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 m ( i j d ) d [ g c d ( i , j ) = d ] = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ ( d i j ) d [ g c d ( i , j ) = 1 ] = ∑ d = 1 n d d ∑ p = 1 ⌊ n d ⌋ μ ( p ) ∑ i = 1 ⌊ n d p ⌋ ∑ j = 1 ⌊ m d p ⌋ ( i j p 2 ) d = ∑ d = 1 n d d ∑ p = 1 ⌊ n d ⌋ μ ( p ) p 2 d ∑ i = 1 ⌊ n d p ⌋ ∑ j = 1 ⌊ m d p ⌋ ( i j ) d \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)^{gcd(i,j)} \\ =\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{m}(\frac{ij}{d})^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}(dij)^d[gcd(i,j)=1] \\ =\sum_{d=1}^{n}d^d\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)\sum_{i=1}^{\lfloor\frac{n}{dp}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dp}\rfloor}(ijp^2)^d \\ =\sum_{d=1}^{n}d^d\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)p^{2d}\sum_{i=1}^{\lfloor\frac{n}{dp}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dp}\rfloor}(ij)^d i=1nj=1mlcm(i,j)gcd(i,j)=d=1ni=1nj=1m(dij)d[gcd(i,j)=d]=d=1ni=1dnj=1dm(dij)d[gcd(i,j)=1]=d=1nddp=1dnμ(p)i=1dpnj=1dpm(ijp2)d=d=1nddp=1dnμ(p)p2di=1dpnj=1dpm(ij)d

看起来不是很能再化简了?

其实我们可以发现, 枚举 d d d再枚举 p p p的复杂度是 O ( N l n ( N ) ) O(Nln(N)) O(Nln(N)), 完全可以过这道题, 那么我们只需要再维护一个 i d i^d id以及它的前缀和就好了。

总复杂度 O ( N l n ( N ) ) O(Nln(N)) O(Nln(N))

代码如下:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <cstring>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 500050
#define MOD 1000000007ll
#define ll long long
int pcnt;
int miu[MX], pri[MX];
ll mul[MX], sum[MX];
bool npr[MX];
void get()
{
	miu[1] = 1; R int i, j, tar;
	for (i = 2; i <= 5e5; ++i)
	{
		if (!npr[i]) npr[i] = true, pri[++pcnt] = i, miu[i] = -1;
		for (j = 1; j <= pcnt; ++j)
		{
			tar = i * pri[j];
			if (tar > 5e5) break;
			npr[tar] = true;
			if (!(i % pri[j])) {miu[tar] = 0; break;}
			miu[tar] = -miu[i];
		}
	}
}
IN ll fpow(ll base, R int tim)
{
	ll ret = 1;
	W (tim)
	{
		if (tim & 1) ret = ret * base % MOD;
		base = base * base % MOD, tim >>= 1;
	}
	return ret;
}
int main(void)
{
	int n, m, bdn, bdm; ll ans = 0, mt, tot;
	scanf("%d%d", &n, &m); get();
	if (n > m) std::swap(n, m);
	for (R int i = 1; i <= m; ++i) mul[i] = 1;
	for (R int i = 1; i <= n; ++i)
	{
		bdn = n / i, bdm = m / i, tot = 0;
		for (R int j = 1; j <= bdm; ++j)
		mul[j] = mul[j] * j % MOD, sum[j] = (sum[j - 1] + mul[j]) % MOD;
		for (R int j = 1; j <= bdn; ++j)
		{
			mt = miu[j] % MOD * mul[j] % MOD * mul[j] % MOD;
			(tot += mt * sum[bdn / j] % MOD * sum[bdm / j] % MOD) %= MOD;
		}
		ans = (ans + fpow(i, i) * tot % MOD) % MOD;
	}
	printf("%lld", (ans + MOD) % MOD);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值