/* 返回顶部 */

Luogu P3312 [SDOI2014]数表

gate

\(\sigma(i)\)表示\(i\)的因子之和。
\(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sigma(gcd(i,j))\ [\sigma(gcd(i,j))\le a]\)
\(\sum\limits_{k=1}^n\sigma(k)\sum\limits_{i=1}^{\frac{n}{k}}\sum\limits_{j=1}^{\frac{m}{k}}\sum_{d|gcd(i,j)}\mu(d)\ [\sigma(k)\le a]\)
\(\sum\limits_{k=1}^n\sigma(k)\sum\limits_{d=1}^{\frac{n}{k}}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor\ [\sigma(k)\le a]\)

\(T=kd\)

\(\sum\limits_{T=1}^n\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(d)\times\sigma(\frac{T}{d})\ [\sigma(\frac{T}{d})\le a]\)

\(f(T,a) = \sum_{d|T}\mu(d)\times\sigma(\frac{T}{d})\ [\sigma(\frac{T}{d})\le a]\)

预处理出\(\sigma(x)\).
将询问离线,按\(a\)从小到大排序。
每次遇到一个询问时,更新所有\(\sigma(x)<a\)\(x\)的贡献。
\(\sigma(x)\)会对\(f(x,a),f(2x,a),f(3x,a),...\)产生影响,贡献即为\(\mu(i)*\sigma(x) (ix=T,x=\frac{T}{i})\)
因为要求前缀和,\(f(x)\)可以用树状数组维护。

时间复杂度\(O(n \log^2 n +q\sqrt n \log n)\)
吸氧可过

code

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define MogeKo qwq
using namespace std;

const int maxn = 1e5+10;
const int N = 1e5;
const int mod = 1ll<<31;

int Q,now,cnt;
int prime[maxn],mu[maxn];
long long sig[maxn],tree[maxn],ans[maxn];
bool vis[maxn];

struct node {
	long long x,y,z,id;
	bool operator < (const node &N) const {
		return z < N.z;
	}
} q[maxn],d[maxn];

long long read() {
	long long x = 0,f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9') {
		x = x*10 + ch-'0';
		ch = getchar();
	}
	return x*f;
}

void Prime() {
	mu[1] = 1;
	for(int i = 2; i <= N; i++) {
		if(!vis[i]) {
			prime[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= cnt && i*prime[j] <= N; j++) {
			vis[i*prime[j]] = true;
			if(i % prime[j] == 0) break;
			mu[i*prime[j]] = -mu[i];
		}
	}
	for(int i = 1; i <= N; i++) {
		for(int j = 1; i*j <= N; j++)
			sig[i*j] += i;
		d[i].z = sig[i];
		d[i].id = i;
	}
	sort(d+1,d+N+1);
}

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

void add(int x,int k) {
	for(; x <= N; x += lowbit(x))
		tree[x] += k;
}

long long query(int x) {
	long long num = 0;
	for(; x; x -= lowbit(x))
		num += tree[x];
	return num;
}

void modify(int x) {
	for(int i = 1; i*x <= N; i++)
		add(i*x,mu[i]*sig[x]);
}

long long solve(int x,int y) {
	int num = 0;
	if(x > y) swap(x,y);
	for(int i = 1,r; i <= x; i = r+1) {
		r = min(x/(x/i), y/(y/i));
		num += (long long)(x/i) * (y/i) * (query(r) - query(i-1));
	}
	return num % mod;
}

int main() {
	Q = read();
	for(int i = 1; i <= Q; i++) {
		q[i].x = read(), q[i].y = read(), q[i].z = read();
		q[i].id = i;
	}
	sort(q+1,q+Q+1);
	Prime();
	now = 0;
	for(int i = 1; i <= Q; i++) {
		while(d[now+1].z <= q[i].z && now < N)
			modify(d[++now].id);
		ans[q[i].id] = solve(q[i].x,q[i].y);
	}
	for(int i = 1; i <= Q; i++)
		printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2020-07-22 14:55  Mogeko  阅读(130)  评论(0编辑  收藏  举报