hdu4746 Mophues 莫比乌斯
Posted 天道酬勤007
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu4746 Mophues 莫比乌斯相关的知识,希望对你有一定的参考价值。
/** 题目:hdu4746 Mophues 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4746 题意:求x,y在给定范围内gcd(x,y)分解素因子的个数<=p的对数。 (n, m, P <= 5×105. Q <=5000). 思路: f(n)表示给定范围内gcd(x,y)==n的对数。 g(n)表示给定范围内gcd(x,y)为n的倍数的对数。 f(n) = sigma[n|d]mu[d/n]*g(d) = sigma[n|d]mu[d/n]*(n/d)*(m/d) ; ans = sigma[1<=x<=min(n,m)]sigma[x|d]mu[d/x]*g(d) = sigma[1<=d<=min(n,m)](g(d)*sigma[x是d的约数]mu[d/x]); sigma[x是d的约数]mu[d/x] 是 g(d)的系数。系数可以用前缀和预处理。 但是本题要求的是gcd(x,y)的分解质因子个数<=p; 所以sigma[x是d的约数]mu[d/x]这里x不仅是d的约数,且要满足x的分解质因子个数<=p (ps:这里的x就是f(n)的n); 定义sum[d]表示 sigma[x是d的约数]mu[d/x], 那么sum[d][num]表示 sigma[x是d的约数,x的分解质因子个数为num]mu[d/x]; 然后处理sum[d][num]表示sum[d][0]~sum[d][num]的前缀和。 然后处理sum[d][num]表示sum[0][num]~sum[d][num]的前缀和。 那么就可以用除法的取值sqrt(N)级别快速计算。 */ #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <iostream> #include <vector> #include <map> using namespace std; typedef long long LL; #define ms(x,y) memset(x,y,sizeof x) typedef pair<int, int> P; const LL INF = 1e10; const int mod = 1e9 + 7; const int maxn = 5e5 + 100; int prime[maxn], tot, not_prime[maxn]; int mu[maxn], sum[maxn][20], cnt[maxn]; void mobius() { mu[1] = 1; tot = 0; for(int i = 2; i < maxn; i++){ if(!not_prime[i]){ mu[i] = -1; prime[++tot] = i; cnt[i] = 1; } for(int j = 1; prime[j]*i<maxn; j++){ not_prime[prime[j]*i] = 1; cnt[prime[j]*i] = cnt[i]+1;///cnt[i]表示i这个数分解素因子的个数。 if(i%prime[j]==0){ mu[prime[j]*i] = 0; break; } mu[prime[j]*i] = -mu[i]; } } for(int i = 1; i < maxn; i++){ for(int j = i; j < maxn; j+=i){ sum[j][cnt[i]] += mu[j/i]; } } for(int i = 1; i < maxn; i++){ for(int j = 1; j < 20; j++){ sum[i][j] += sum[i][j-1]; } } for(int j = 0; j < 20; j++){ for(int i = 1; i< maxn; i++){ sum[i][j] += sum[i-1][j]; } } } LL solve(int n,int m,int p) { if(n>m) swap(n,m); LL ans = 0; int last; for(int i = 1; i <= n; i = last+1){ last = min(n/(n/i),m/(m/i)); ans += (LL)(sum[last][p]-sum[i-1][p])*(n/i)*(m/i); } return ans; } int main() { //freopen("YYnoGCD.in","r",stdin); //freopen("YYnoGCD.out","w",stdout); //freopen("in.txt","r",stdin); int n, m, p; int T; mobius(); cin>>T; while(T--){ scanf("%d%d%d",&n,&m,&p); if(p>19){ printf("%lld\n",(LL)n*m); continue; } printf("%lld\n",solve(n,m,p)); } return 0; }
以上是关于hdu4746 Mophues 莫比乌斯的主要内容,如果未能解决你的问题,请参考以下文章