【bzoj3309】DZY Loves Math 莫比乌斯反演+线性筛

题目描述

对于正整数x,定义f(x)为x所含质因子的最大幂指数。例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0。
给定正整数n,m,求$\sum\limits_{i=1}^n\sum\limits_{j=1}^mf(\gcd(i,j))$

输入

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

输出

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

样例输入

4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957

样例输出

35793453939901
14225956593420
4332838845846
15400094813


题解

莫比乌斯反演+线性筛

(为了方便,以下公式默认$n\le m$)

首先有公式:

$\ \ \ \ \sum\limits_{i=1}^n\sum\limits_{j=1}^mf(\gcd(i,j))\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=d]\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^{\lfloor\frac nd\rfloor}\sum\limits_{j=1}^{\lfloor\frac md\rfloor}[\gcd(i,j)=1]\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^{\lfloor\frac nd\rfloor}\sum\limits_{j=1}^{\lfloor\frac md\rfloor}\sum\limits_{p|\gcd(i,j)}\mu(p)\\=\sum\limits_{d=1}^nf(d)\sum\limits_{p=1}^{\lfloor\frac nd\rfloor}\mu(p)\lfloor\frac n{dp}\rfloor\lfloor\frac m{dp}\rfloor$

然后令$D=dp$,可以得到:

$\ \ \ \ \sum\limits_{d=1}^nf(d)\sum\limits_{p=1}^{\lfloor\frac nd\rfloor}\mu(p)\lfloor\frac n{dp}\rfloor\lfloor\frac m{dp}\rfloor\\=\sum\limits_{D=1}^n\lfloor\frac n{D}\rfloor\lfloor\frac m{D}\rfloor\sum\limits_{p|D}\mu(p)f(\frac Dp)$

这个形式看起来非常妙,然而$n$和$m$有$10^7$之大,使用枚举倍数的调和级数时间复杂度预处理的方法的话肯定会GG(亲测就算加上$\mu\neq 0$的优化也是过不去的)。

然而经过打表可以发现,对于每个$D$,$g(D)=\sum\limits_{p|D}\mu(p)f(\frac Dp)$都是$0$、$-1$或$1$中的一个值。

至此可以猜测想出结论:$g(D)$的值只与其质因子的构成有关。

事实上,具体的结论是:当$D\neq 1$时,令$D=p_1^{a_1}p_2^{a_2}...p_k^{a_k}$,则当且仅当$a_1=a_2=...=a_k$时,$g(D)=(-1)^{k+1}$;否则$g(D)=0$。

证明

观察$g(D)$的形式:只有当$p$中不含有平方因子时,$\mu(p)$才不为0。所以相当于:$D$的所有质因子中,每个质因子有选和不选两种选择,选了的话它的贡献就会减1。

先证明$a_1$、$a_2$、...、$a_k$不全相等时,$g(D)=0$:如果所有质因子的次数不全相等,那么考虑次数最小的那个质因子,它无论是否选择都不会影响$f(\frac Dp)$的值,只是差在$\mu(p)$的正负。这样选它和不选它,产生的贡献正好正负抵消,因此$g(D)$一定是0。

再考虑$a_1=a_2=...=a_k$的情况:当且仅当每个质因子都选择时,$f(\frac Dp)$等于$a-1$,否则等于$a$。那么如果把$a-1$的那次贡献看作$a$,那么答案应该是0。所以只需要考虑把$a-1$看成$a$的变化。显然当$k$为奇数时$\mu(p)$为负,$a-1$的贡献为负,因此答案为$1$;否则$a-1$的贡献为正,答案为$-1$。

所以就可以根据每个数的质因子构成来线性筛出每个数的$g$值。具体做法:如果把每个数写成$v·p^a$的形式,那么维护每个数的:$v$的每个质因子的次数(不全相同则为-1)、$a$的值以及质因子种类数$k$。根据这些很容易计算出当前数的$g$。注意需要考虑$v=1$的情况。

然后就可以直接求前缀和,对于每组询问枚举商即可。

时间复杂度$O(n+T\sqrt n)$

#include <cstdio>
#include <algorithm>
#define N 10000010
#define k 10000000
using namespace std;
int v[N] , c[N] , cnt[N] , prime[N] , tot , sum[N];
bool np[N];
int main()
{
	int i , j , T , n , m , last;
	long long ans;
	for(i = 2 ; i <= k ; i ++ )
	{
		if(!np[i]) prime[++tot] = i , c[i] = cnt[i] = 1;
		for(j = 1 ; j <= tot && i * prime[j] <= k ; j ++ )
		{
			np[i * prime[j]] = 1;
			if(i % prime[j] == 0)
			{
				v[i * prime[j]] = v[i] , c[i * prime[j]] = c[i] + 1 , cnt[i * prime[j]] = cnt[i];
				break;
			}
			else
			{
				if(!v[i] || v[i] == c[i]) v[i * prime[j]] = c[i];
				else v[i * prime[j]] = -1;
				c[i * prime[j]] = 1 , cnt[i * prime[j]] = cnt[i] + 1;
			}
		}
		if(v[i] && v[i] != c[i]) sum[i] = sum[i - 1];
		else if(cnt[i] & 1) sum[i] = sum[i - 1] + 1;
		else sum[i] = sum[i - 1] - 1;
	}
	scanf("%d" , &T);
	while(T -- )
	{
		scanf("%d%d" , &n , &m);
		ans = 0;
		for(i = 1 ; i <= n && i <= m ; i = last + 1)
			last = min(n / (n / i) , m / (m / i)) , ans += (long long)(n / i) * (m / i) * (sum[last] - sum[i - 1]);
		printf("%lld\n" , ans);
	}
	return 0;
}

 

posted @ 2017-09-13 14:05  GXZlegend  阅读(426)  评论(2编辑  收藏  举报