HDU 4746. Mophues

链接

http://acm.hdu.edu.cn/showproblem.php?pid=4746

题意

求 $1\le i \le N,1 \le j \le M$ 且 $\gcd(i,j)$ 的质因子个数小于等于 $p$ 的对数。

思路

根据莫比乌斯反演公式 $F(n)=\sum_{n\mid d}f(d)$,

记 $f(d)$ 为 $1\le i \le N,1 \le j \le M$ 且 $\gcd(i,j)=d$ 的对数,

记 $F(d)$ 为 $1\le i \le N,1 \le j \le M$ 且 $d\mid \gcd(i,j)$ 的对数,

易得 $F(d)=\lfloor\frac{N}{d}\rfloor\lfloor\frac{M}{d}\rfloor$。

可推得 $F(n)=\sum_{n\mid d}f(d)\Leftrightarrow f(n)=\sum_{n\mid d}\mu(\frac{d}{n})F(d)=\sum_{n\mid d}\mu(\frac{d}{n})\lfloor\frac{N}{d}\rfloor\lfloor\frac{M}{d}\rfloor$。

根据题意,设 $k$ 是质因子个数小于等于 $p$ 个的数,

$\sum_k f(k)=\sum_k\sum_{k\mid d}\mu(\frac{d}{k})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor=\sum_d({\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor}\sum_{k\mid d}\mu(\frac{d}{k}))$。

$N,M$ 最大值为 $500000$,最大质因子个数为 $18$。

记 $g_{i,j}$ 为 $i$ 的所有质因子数量小于等于 $j$ 的因子 $k$ 的 $\mu(\frac{i}{k})$ 和,$sum_{i,j}=\sum_{i’}^i\sum_{j’}^j{g_{i’,j’}}$ ,预处理 $sum$。

  • 当 $p>18$ 时,直接输出 $N*M$。
  • 当 $p\le 18$ 时,数论分块 $O(\sqrt{n})$ 求解。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
// head
const int N=5e5+5;
int mn[N],mu[N],cnt[N],sum[N][20];
VI p;
void get_mu(int n) {
mu[1]=1;
for(int i=2;i<=n;i++) {
if(!mn[i]) mn[i]=i,mu[i]=-1,p.PB(i),cnt[i]=1;
for(auto x:p) {
if(x*i>n) break;
cnt[i*x]=cnt[i]+1;
mn[x*i]=x;
if(i%x==0) {mu[x*i]=0;break;}
mu[x*i]=-mu[i];
}
}
}
void init(int n) {
get_mu(n);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=i)
sum[j][cnt[i]]+=mu[j/i];
for(int i=1;i<=n;i++)
for(int j=0;j<=18;j++) {
if(i-1>=0) sum[i][j]+=sum[i-1][j];
if(j-1>=0) sum[i][j]+=sum[i][j-1];
if(i-1>=0&&j-1>=0) sum[i][j]-=sum[i-1][j-1];
}
}
LL solve(int t,int n,int m) {
LL res=0;
int lim=min(n,m);
for(int l=1,r;l<=lim;l=r+1) {
r=min(n/(n/l),m/(m/l));
res+=1ll*(sum[r][t]-sum[l-1][t])*(n/l)*(m/l);
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
init(5e5);
int q;cin>>q;
while(q--) {
int n,m,t;cin>>n>>m>>t;
if(t>=19) cout<<1ll*n*m<<'\n';
else cout<<solve(t,n,m)<<'\n';
}
return 0;
}