链接
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;
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; }
|