(每日一题)P3312 [SDOI2014]数表(经典莫比乌斯反演 + 树状数组维护离线询问)

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


每日一题(莫反 / 多项式 / 母函数 / 群论) 2021.4.11 莫反

P3312 [SDOI2014]数表(经典莫比乌斯反演 + 树状数组维护离线询问)

Problem
在这里插入图片描述
1 ≤ n , m ≤ 1 0 5 , 1 ≤ Q ≤ 2 × 1 0 4 1≤n,m≤10 ^5 ,1\le Q\le 2\times 10^4 1n,m105,1Q2×104

Solution
在这里插入图片描述
Code

注意mu函数可能是负的,所以一定要记得 + mod % mod

// Problem: P3312 [SDOI2014]数表
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3312
// Memory Limit: 125 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define int long long
using namespace std;
const int N = 2e5 + 7, R = 2e5, M = 2e4 + 7, mod = 1ll << 31;


int n, m;
int sigma[N], g[N], mu[N];
int primes[N], cnt;
bool vis[N];
int ans[N];
int tr[N];

struct question
{
	int n, m, a, id;
	bool operator < (const question &t) const {
		return a < t.a;
	}
} que[M];

struct number
{
	int x;
	bool operator < (const number &t) const {
		return sigma[x] < sigma[t.x];
	}
} a[N];


inline int lowbit(int x)
{
	return x & (- x);
}

void add_tr(int x, int val)
{
	for(; x <= R; x += x & (- x)) {
		(tr[x] += val) %= mod;
	}
}

int query_tr(int x)
{
	int res = 0;
	for(; x >= 1; x &= x - 1) {
		(res += tr[x]) %= mod;
	}
	return res;
}

void insert_tr(int x)
{
	for(int k = 1; x * k <= R; ++ k) {
		add_tr(x * k, (mu[k] * sigma[x] + mod) % mod);
	}
}

void init(int n)
{
	sigma[1] = g[1] = mu[1] = 1;
	for(int i = 2; i <= n; ++ i) {
		if(vis[i] == 0) {
			primes[ ++ cnt] = i;
			sigma[i] = g[i] = i + 1;
			mu[i] = -1;
		}
		for(int j = 1; j <= cnt && i * primes[j] <= n; ++ j) {
			vis[i * primes[j]] = true;
			if(i % primes[j] == 0) {
				mu[i * primes[j]] = 0;
				g[i * primes[j]] = g[i] * primes[j] + 1;
				sigma[i * primes[j]] = sigma[i] / g[i] * g[i * primes[j]];
				break;
			}
			mu[i * primes[j]] -= mu[i];
			g[i * primes[j]] = primes[j] + 1;
			sigma[i * primes[j]] = sigma[i] * sigma[primes[j]];
		}
	}
	for(int i = 1; i <= n; ++ i)
		a[i].x = i;
	sort(a + 1, a + 1 + n);
}

int query(int n, int m)
{
	int res = 0, last = 0, now;
	for(int l = 1, r; l <= n; l = r + 1, last = now) {
		r = min(n / (n / l), m / (m / l));
		now = query_tr(r);//这次的 r 就是下次的 l
		(res += ((now - last + mod) % mod * (n / l) % mod * (m / l) % mod) % mod) %= mod;
	}
	return res;
}

signed main()
{
	init(N - 7);
	int Q;
	scanf("%lld", &Q);
	for(int i = 1, a; i <= Q; ++ i) {
		scanf("%lld%lld%lld", &n, &m, &a);
		if(n > m) swap(n, m);
		que[i] = {n, m, a, i};
	}
	sort(que + 1, que + 1 + Q);
	int j = 1;
	for(int i = 1; i <= Q; ++ i) {
		for(; j <= R && sigma[a[j].x] <= que[i].a; ++ j) 
			insert_tr(a[j].x);
		ans[que[i].id] = query(que[i].n, que[i].m);
	}
	for(int i = 1; i <= Q; ++ i) {
		printf("%lld\n", ans[i]);
	}
	return 0;
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页