题意
(T(T le 10000))次询问,每次给出(a, b(1 le a, b le 10^7)),求
其中(f(n))表示(n)所含质因子的最大幂指数。(f(1)=0)。
分析
以下默认(a le b)
$$ egin{align} & sum_{i=1}^{a} sum_{j=1}^{b} f((i, j)) \ = & sum_{d=1}^{a} f(d) sum_{i=1}^{a'} sum_{j=1}^{b'} [(i, j)=1] & left( a' = left lfloor frac{a}{d} ight floor, b' = left lfloor frac{b}{d} ight floor ight) \ = & sum_{d=1}^{a} f(d) sum_{i=1}^{a'} sum_{j=1}^{b'} sum_{k|(i, j)} mu(k) \ = & sum_{d=1}^{a} f(d) sum_{k=1}^{left lfloor frac{a}{d} ight floor} mu(k) left lfloor frac{a}{kd} ight floor left lfloor frac{b}{kd} ight floor \ = & sum_{T=1}^{a} left lfloor frac{a}{T} ight floor left lfloor frac{b}{T} ight floor sum_{d|T} mu(d) f(frac{T}{d}) \ end{align} $$
考虑(g(n) = sum_{i|n} mu(i) f(frac{n}{i})):
令(S = \{ p_i \}),(p_i)为(n)的质因子,则只有当(i=prod_{j in S' subseteq S} j)时才对(g(n))有贡献。
令(A subseteq S)表示指数最大(假设为(y))的质因子集合,(B=S-A)。则(i)可以看做从(A)中选出一些质因子再从(B)中选出一些质因子组合一下。
由于(f(frac{n}{i}))的取值只取决于(i)中从(A)集合取的子集(可以发现(f)要么是(a),要么是(a-1),由(A)来决定的),所以我们只需考虑(A)的子集。
当(B
eq varnothing)时,当选的(A)的子集确定后即(f(frac{n}{i}))相同时,由于从(B)中奇偶大小子集的个数相同,因此奇数个质因子的(i)和偶数个质因子的(i)的个数相同,所以(mu(i))的和为(0)。所以(g(n)=0)。
当(B = varnothing)时,则只有当(i=prod_{j in S} j)时(f(frac{n}{i})=y-1),否则(f(frac{n}{i})=y)。而当(f(frac{n}{i})=y)时,对于这个非全集的所有子集,奇数大小的子集和偶数大小的子集个数相差为1,计算一下就知道这种情况的贡献是((-1)^{|S|+1} a)。对于全集,贡献是((-1)^{|S|} (a-1))。所以(g(n) = (-1)^{|S|} (a-1) + (-1)^{|S|+1} a = (-1)^{|S|+1})
于是线性筛筛出(g(n))即可。
题解
至于查询,分块就行了。
复杂度(O(b+Tb^{0.5}))
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Lim=10000005;
int N, x[10005], y[10005], f[Lim], p[Lim], mu[Lim], cnt;
bool np[Lim];
ll sum[Lim];
void init() {
mu[1]=1;
for(int i=2; i<=N; ++i) {
if(!np[i]) p[cnt++]=i, mu[i]=-1;
for(int j=0; j<cnt; ++j) {
int t=p[j]*i; if(t>N) break;
np[t]=1;
if(i%p[j]==0) break;
mu[t]=-mu[i];
}
}
for(int i=2; i<=N; ++i) {
if(mu[i]) {
sum[i]=-mu[i];
}
}
for(int i=N; i>=2; --i) {
if(sum[i]) {
for(ll j=(ll)i*i; j<=N; j*=i) {
sum[j]=sum[i];
}
}
}
for(int i=2; i<=N; ++i) {
sum[i]+=sum[i-1];
}
}
int main() {
int T; scanf("%d", &T);
for(int i=1; i<=T; ++i) scanf("%d%d", &x[i], &y[i]), N=max(N, x[i]), N=max(N, y[i]);
init();
for(int tt=1; tt<=T; ++tt) {
int a=x[tt], b=y[tt];
if(a>b) swap(a, b);
int now=1;
ll ans=0;
for(int i=1; i<=a; i=now+1) {
now=min(a/(a/i), b/(b/i));
ans+=(ll)(a/i)*(ll)(b/i)*(sum[now]-sum[i-1]);
}
printf("%lld
", ans);
}
return 0;
}