【BZOJ 3309】DZY Loves Math

http://www.lydsy.com/JudgeOnline/problem.php?id=3309

\[\sum_{T=1}^{min(a,b)}\sum_{d|T}f(d)\mu(\frac Td)\lfloor\frac aT\rfloor\lfloor\frac bT\rfloor \]

\(g(n)=\sum\limits_{d|n}f(d)\mu(\frac nd)\)
假设n的质因子分解为\(p_1^{c_1},p_2^{c_2}\dots p_m^{c_m}\),设最大的质因子次数为a,质因子次数为a的有q个,那么

\[g(n)=a*e(n)-e(\frac{n}{\prod_i[c_i==a]p_i^{c_i}})*(-1)^q \]

可以看出当质因子的次数\(c_1,c_2\dots c_m\)都相等时g(n)是\((-1)^{m+1}\),否则g(n)为0。
线筛g就可以\(O(\sqrt n)\)回答询问了。
g的线筛好难想啊!!!维护last表示除掉最小质因子后的数,t表示最小质因子的次数。

UPD:我写的筛法好残啊,其实直接筛质因子次数都为1的,再枚举k次方就可以了qwq

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1E7;

bool notp[N + 3];
int prime[N + 3], num = 0, last[N + 3], t[N + 3];
ll g[N + 3], ans;

void Euler_shai() {
	for (int i = 2; i <= N; ++i) {
		if (!notp[i]) {
			prime[++num] = i;
			last[i] = t[i] = g[i] = 1;
		}
		for (int j = 1, p = prime[j]; j <= num && 1ll * i * p <= N; p = prime[++j]) {
			notp[i * p] = true;
			if (i % p == 0) {
				last[i * p] = last[i];
				t[i * p] = t[i] + 1;
				if (last[i] == 1) g[i * p] = 1;
				else g[i * p] = (t[last[i]] == t[i * p] ? -g[last[i]] : 0);
				break;
			} else {
				last[i * p] = i;
				t[i * p] = 1;
				g[i * p] = (t[i] == 1 ? -g[i] : 0);
			}
		}
	}
	for (int i = 2; i <= N; ++i) g[i] += g[i - 1];
}

int main() {
	Euler_shai();
	int T, a, b; scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &a, &b);
		if (a > b) swap(a, b);
		ans = 0;
		for (int T = 1, y; T <= a; T = y + 1) {
			y = min(a / (a / T), b / (b / T));
			ans += (g[y] - g[T - 1]) * (a / y) * (b / y);
		}
		printf("%lld\n", ans);
	}
	return 0;
}
posted @ 2017-01-08 15:24  abclzr  阅读(264)  评论(0编辑  收藏  举报