推式子的时候默认 (n < m)
令 (sigma(i)) 表示 (i) 的约数和
[ ans= sumlimits _{i=1}^nsumlimits_{j=1}^{n} sigma(gcd(i,j))\
=sumlimits_{d=1}^{n} sum limits_{i=1}^{frac{n}{d}} sum limits_{j=1}^{frac{m}{d}} sigma(d)[gcd(i,j)==1]\
=sumlimits_{d=1}^{n} sum limits_{i=1}^{frac{n}{d}} sum limits_{j=1}^{frac{m}{d}} sumlimits_{x|d}mu(x) sigma(d)\
=sumlimits_{d=1}^{n} sigma(d) sum limits_{i=1}^{frac{n}{d}} sum limits_{j=1}^{frac{m}{d}} sumlimits_{x|d}mu(x)\
=sumlimits_{d=1}^{n} sigma(d) sumlimits_{x=1}^{frac{n}{d}}mu(x) dfrac{n}{dx} dfrac{m}{dx}\
sumlimits_{d=1}^n sigma(d) sumlimits_{T=1}^{n} mu(dfrac{T}{d})dfrac{n}{T} dfrac{m}{T}(T=dx)\
=sumlimits_{T=1}^{n}dfrac{n}{T} dfrac{m}{T}sumlimits_{d|T}sigma(d)mu(dfrac{T}{d})\
]
先线性筛出 (mu) ,(sigma) 可以 (O(nlog n)) 暴力算,前面套个整除分块即可。
但是加上 (a) 的限制之后。。。
发现只有 (sigma(i)le a) 的时候才可以对于那个 (T) 产生贡献。
所以考虑离线询问,将 (a) 从小到大排序,还要预处理所有的 (sigma(i)) 从小到大排序,用树状数组暴力修改即可。
附赠一组较强样数据供调试
Input
1
25291 26958 42646
Output
235628669
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
#define int long long
inline unsigned read() {
unsigned x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int N = 20005;
const int M = 100005;
const int mod = 1ll << 31;
int ans[N], tr[M];
bool vis[M];
int mu[M], pri[M], cnt, q, it = 1;
struct node {
int n, m, a, id;
inline bool operator<(const node&rhs)const{return a < rhs.a;}
}a[N];
struct fact {
int id, x;
inline bool operator<(const fact&rhs)const{return x < rhs.x;}
}f[M];
void add(int x, int d) {
for (int i = x; i < M; i += i & -i) tr[i] += d;
}
int ask(int x) {
int res = 0;
for (int i = x; i > 0; i -= i & -i) res += tr[i];
return res;
}
void Sieve() {
mu[1] = 1;
for (int i = 2; i < M; ++ i) {
if (! vis[i]) pri[++ cnt] = i, mu[i] = -1;
for (int j = 1; i * pri[j] < M; ++ j) {
vis[i * pri[j]] = 1;
if(i % pri[j] == 0) break;
mu[i * pri[j]] = - mu[i];
}
}
for (int i = 1; i < M; ++ i)
for (int j = 1; i * j < M; ++ j)
f[i * j].x += i;
for(int i = 1; i < M; ++ i) f[i].id = i;
sort(f + 1, f + M);
}
signed main() {
Sieve();
q = read();
for (int i = 1; i <= q; ++ i)
a[i].n = read(), a[i].m = read(), a[i].a = read(), a[i].id = i;
sort(a + 1, a + q + 1);
for (int i = 1; i <= q; ++ i) {
while (it < M && f[it].x <= a[i].a) {
int t = f[it].id;
for (int j = 1; j * t < M; ++ j) add(j * t, f[it].x * mu[j]);
++ it;
}
int res = 0, n = a[i].n, m = a[i].m;
if (n > m) swap(n, m);
for (int l = 1, r; l <= n; l = r + 1)
r = min(n / (n / l), m / (m / l)), res += (n / l) * (m / l) * (ask(r) - ask(l - 1));
ans[a[i].id] = res;
}
for (int i = 1; i <= q; ++ i) printf("%lld
", ans[i] % mod);
return 0;
}