设(sigma(i))表示(i)的因子之和。
(sumlimits_{i=1}^nsumlimits_{j=1}^msigma(gcd(i,j)) [sigma(gcd(i,j))le a])
(sumlimits_{k=1}^nsigma(k)sumlimits_{i=1}^{frac{n}{k}}sumlimits_{j=1}^{frac{m}{k}}sum_{d|gcd(i,j)}mu(d) [sigma(k)le a])
(sumlimits_{k=1}^nsigma(k)sumlimits_{d=1}^{frac{n}{k}}mu(d)lfloorfrac{n}{kd}
floorlfloorfrac{m}{kd}
floor [sigma(k)le a])
设(T=kd)
(sumlimits_{T=1}^nlfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsum_{d|T}mu(d) imessigma(frac{T}{d}) [sigma(frac{T}{d})le a])
设(f(T,a) = sum_{d|T}mu(d) imessigma(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 +qsqrt 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
",ans[i]);
return 0;
}