[BZOJ 3309] DZY Loves Math

BZOJ传送门

Description

对于正整数 n n n,定义 f ( n ) f(n) f(n) n n n所含质因子的最大幂指数。例如 f ( 1960 ) = f ( 2 3 ∗ 5 1 ∗ 7 2 ) = 3 , f ( 10007 ) = 1 , f ( 1 ) = 0 f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0 f(1960)=f(235172)=3,f(10007)=1,f(1)=0
给定正整数 a , b a,b a,b,求 ∑ ∑ f ( g c d ( i , j ) ) ( i = 1.. a , j = 1.. b ) \sum\sum f(gcd(i,j)) (i=1..a, j=1..b) f(gcd(i,j))(i=1..a,j=1..b)

Input

第一行一个数 T T T,表示询问数。
接下来 T T T行,每行两个数 a , b a,b a,b,表示一个询问。

Output

对于每一个询问,输出一行一个非负整数作为回答。

Sample Input

4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
 

Sample Output

35793453939901
14225956593420
4332838845846
15400094813

HINT

【数据规模】

T ≤ 10000 T\le 10000 T10000

1 ≤ a , b ≤ 1 0 7 1\le a,b\le 10^7 1a,b107

解题分析

还是一波推式子:(不妨设 n ≤ m n\le m nm
∑ i = 1 n ∑ j = 1 m f ( g c d ( i , j ) ) = ∑ d = 1 n f ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ g c d ( i , j ) = 1 ] = ∑ d = 1 n f ( d ) ∑ e = 1 ⌊ n d ⌋ μ ( e ) ⌊ n d e ⌋ ⌊ m d e ⌋ \sum_{i=1}^{n}\sum_{j=1}^mf(gcd(i,j)) \\ =\sum_{d=1}^{n}f(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)=1] \\ =\sum_{d=1}^{n}f(d)\sum_{e=1}^{\lfloor\frac{n}{d}\rfloor}\mu(e)\lfloor\frac{n}{de}\rfloor\lfloor\frac{m}{de}\rfloor i=1nj=1mf(gcd(i,j))=d=1nf(d)i=1dnj=1dm[gcd(i,j)=1]=d=1nf(d)e=1dnμ(e)dendem
d e = T de=T de=T, 那么:
∑ d = 1 n f ( d ) ∑ e = 1 ⌊ n d ⌋ μ ( e ) ⌊ n d e ⌋ ⌊ m d e ⌋ = ∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ d ∣ T μ ( d ) f ( T d ) \sum_{d=1}^{n}f(d)\sum_{e=1}^{\lfloor\frac{n}{d}\rfloor}\mu(e)\lfloor\frac{n}{de}\rfloor\lfloor\frac{m}{de}\rfloor \\ =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(d)f(\frac{T}{d}) d=1nf(d)e=1dnμ(e)dendem=T=1nTnTmdTμ(d)f(dT)
考虑如何计算 G ( T ) = ∑ d ∣ T μ ( d ) f ( T d ) G(T)=\sum_{d|T}\mu(d)f(\frac{T}{d}) G(T)=dTμ(d)f(dT)。 显然我们要让 μ ( d ) ≠ 0 \mu(d)\ne 0 μ(d)̸=0, 从 T T T内取得的相同质因数就不应该超过一个。

考虑 T = p 1 a × . . . × p n a × p n + 1 b 1 × . . . × p n + m b m T=p_1^a\times ...\times p_n^a\times p_{n+1}^{b_1}\times ...\times p_{n+m}^{b_m} T=p1a×...×pna×pn+1b1×...×pn+mbm, 其中 a > b i a>b_i a>bi

那么我们有两种选择:

  • 将前 n n n个最高次幂的选到 d d d中, 后面随意选择, 这样得到的贡献是 ( f ( T ) − 1 ) × ( − 1 ) n × ∑ i = 0 m ( m i ) ( − 1 ) i (f(T)-1)\times(-1)^n\times\sum_{i=0}^{m}\binom{m}{i}(-1)^i (f(T)1)×(1)n×i=0m(im)(1)i, 注意到后面当 m ≠ 0 m\ne 0 m̸=0的时候, 值为0, 当 m = 0 m=0 m=0的时候, 值为 ( f ( T ) − 1 ) × ( − 1 ) n (f(T)-1)\times (-1)^n (f(T)1)×(1)n
  • 不选完前 n n n个, 后面随意选择, 这样得到的贡献是 f ( T ) × ∑ i = 0 n − 1 ( n i ) × ( − 1 ) n × ∑ j = 0 m ( m j ) ( − 1 ) j f(T)\times \sum_{i=0}^{n-1}\binom{n}{i}\times (-1)^n\times \sum_{j=0}^{m}\binom{m}{j}(-1)^j f(T)×i=0n1(in)×(1)n×j=0m(jm)(1)j, 同理当 m ≠ 0 m\ne 0 m̸=0的时候值为 0 0 0, 当 m = 0 m=0 m=0的时候, 值为 f ( T ) × ( − 1 ) ( n + 1 ) f(T)\times (-1)^{(n+1)} f(T)×(1)(n+1)

综上, G ( T ) G(T) G(T)当且仅当 T T T的质因数的指数齐次的时候有值, 值为 ( − 1 ) n + 1 (-1)^{n+1} (1)n+1

所以我们可以暴力筛出所有质数, 然后 D F S DFS DFS或筛出得到一次齐次的所有数, 然后向上累乘即可。 总复杂度 O ( N + T N ) O(N+T\sqrt N) O(N+TN )

代码如下:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cstring>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 10000005
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
int tim[MX], num[MX], pri[MX], sum[MX], buc[MX];
bool npr[MX], vis[MX];
int pcnt, tot;
void get_pri()
{
	R int i, j, tar;
	for (i = 2; i <= 1e7; ++i)
	{
		if (!npr[i]) pri[++pcnt] = i, num[i] = 1;
		for (j = 1; j <= pcnt; ++j)
		{
			tar = pri[j] * i;
			if (tar > 1e7) break;
			npr[tar] = true;
			if (!(i % pri[j])) break;
		}
	}
}
void DFS(R int pos, R int now, R int dep)
{
	buc[++tot] = now, num[now] = dep;
	long long tar;
	for (R int i = pos + 1; i <= pcnt; ++i)
	{
		tar = 1ll * now * pri[i];
		if (tar > 1e7) break;
		DFS(i, tar, dep + 1);
	}
}
int main(void)
{
	get_pri();
	DFS(0, 1, 0); long long mul;
	for (R int i = 2; i <= tot; ++i)
	{
		for (mul = 1ll * buc[i] * buc[i]; mul <= 1e7; mul = mul * buc[i])
		num[mul] = num[buc[i]];
	}
	for (R int i = 1; i <= 1e7; ++i)
	{
		if (!num[i]) sum[i] = sum[i - 1];
		else sum[i] = sum[i - 1] + ((num[i] & 1) ? 1 : -1);
	}
	int T, n, m, lef, rig; in(T); long long ans;
	W (T--)
	{
		in(n), in(m); ans = 0;
		if (n > m) std::swap(n, m);
		for (lef = 1; lef <= n; lef = rig + 1)
		{
			rig = std::min(n / (n / lef), m / (m / lef));
			ans += 1ll * (n / lef) * (m / lef) * (sum[rig] - sum[lef - 1]);
		}
		printf("%lld\n", ans);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值