HDU 4746 Mophues(莫比乌斯反演)
Posted xiuwenli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4746 Mophues(莫比乌斯反演)相关的知识,希望对你有一定的参考价值。
题意:求(1leq i leq N,1leq j leq M,gcd(i,j))的质因子个于等于p的对数。
分析:加上了对质因子个数的限制。
设(f(d):[gcd(i,j)=d]) , (F(d):[d|gcd(i,j)]) ,k是满足质因子<=p的数。
则(ans = sum_{k}f(k) = sum_{k}sum_{k|d}u(frac{d}{k})lfloor frac{N}{d}
floor lfloorfrac{M}{d}
floor = sum_{d}lfloor frac{N}{d}
floor lfloorfrac{M}{d}
floorsum_{k|d}u(frac{d}{k}))
(sum_{k|d}u(frac{d}{k}))可以预处理得到。
由于限制了质因子的个数,并且我们还想用分块的方法求出最后答案,于是设(sum(a,b):sum_{i=1}^{a}sum_{k|i且k质因子个数leq j}u(frac{i}{k}))。在打出莫比乌斯函数表后,可以在预处理出(sum(a,b)表),由于1e6以内的数质因子个数不会超过20,因此第二维开到20即可。
那么计算结果时可以分块加速求出ans的值。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=5e5+5;
bool vis[maxn];
int prime[maxn],mu[maxn];
int sum[maxn][20];
int pricnt[maxn];
void init(){
memset(vis,false,sizeof(vis));
mu[1] = 1;
prime[0] = 0;
int cnt=0;
for(int i=2;i<maxn;++i){
if(!vis[i]){
mu[i] = -1;
pricnt[i] = 1;
prime[++cnt] = i;
}
for(int j=1;j<=cnt;++j){
if(i*prime[j] >= maxn) break;
pricnt[i*prime[j]] = pricnt[i]+1;
vis[i*prime[j]] = true;
if(i % prime[j]){
mu[i*prime[j]] = -mu[i];
}
else{
mu[i*prime[j]] = 0;
break;
}
}
}
}
void prepare(){
for(int i=1;i<maxn;++i){
for(int j= i;j<maxn;j+=i){
sum[j][pricnt[i]] += mu[j/i];
}
}
for(int i=1;i<maxn;++i){
for(int j =0;j<20;++j){
sum[i][j] +=sum[i-1][j];
}
}
for(int i=1;i<maxn;++i){
for(int j=1;j<20;++j){
sum[i][j] +=sum[i][j-1];
}
}
}
LL gao(LL n,LL m,LL p) //枚举p
{
LL ans = 0;
for(int i=1,j;i<=n;i=j+1){
j = min(n/(n/i),m/(m/i));
ans += (sum[j][p]-sum[i-1][p])*(n/i)*(m/i);
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
init();
prepare();
LL N,M,p;
int T; scanf("%d",&T);
while(T--){
scanf("%lld %lld %lld",&N, &M,&p);
LL res=0;
if(p>=20){
res = N*M;
}
else{
if(N>M) swap(N,M);
res = gao(N,M,p);
}
printf("%lld
",res);
}
return 0;
}
以上是关于HDU 4746 Mophues(莫比乌斯反演)的主要内容,如果未能解决你的问题,请参考以下文章