HDU 4746 Mophues(莫比乌斯反演)

Mophues

As we know, any positive integer C ( C >= 2 ) can be written as the multiply of some prime numbers:
C = p1×p2× p3× … × pk
which p1, p2 … pk are all prime numbers.For example, if C = 24, then:
24 = 2 × 2 × 2 × 3
here, p1 = p2 = p3 = 2, p4 = 3, k = 4

Given two integers P and C. if k<=P( k is the number of C’s prime factors), we call C a lucky number of P.

Now, XXX needs to count the number of pairs (a, b), which 1<=a<=n , 1<=b<=m, and gcd(a,b) is a lucky number of a given P ( “gcd” means “greatest common divisor”).

Please note that we define 1 as lucky number of any non-negative integers because 1 has no prime factor.

Input
The first line of input is an integer Q meaning that there are Q test cases.
Then Q lines follow, each line is a test case and each test case contains three non-negative numbers: n, m and P (n, m, P <= 5×10 5. Q <=5000).

Output
For each test case, print the number of pairs (a, b), which 1<=a<=n , 1<=b<=m, and gcd(a,b) is a lucky number of P.

Sample Input

2
10 10 0
10 10 1

Sample Output

63
93

题意
g c d ( a , b ) gcd(a,b) gcd(a,b)的素因子个数小于 P P P的对 ( a , b ) ( 1 &lt; = a &lt; = n , 1 &lt; = b &lt; = m ) (a,b)(1&lt;=a&lt;=n,1&lt;=b&lt;=m) (a,b)(1<=a<=n,1<=b<=m)的个数

题解
莫比乌斯反演。
f ( d ) f(d) f(d)表示 g c d ( a , b ) = d gcd(a,b)=d gcd(a,b)=d a , b a,b a,b满足题意的对 ( a , b ) (a,b) (a,b)的个数, F ( d ) F(d) F(d)表示满足 d ∣ g c d ( a , b ) d|gcd(a,b) dgcd(a,b) a , b a,b a,b满足题意的对 ( a , b ) (a,b) (a,b)的个数。
关系式:
F ( x ) = Σ x ∣ d f ( d ) F(x)=\Sigma_{x|d}f(d) F(x)=Σxdf(d)
F ( d ) F(d) F(d)显然:
F ( x ) = n x ∗ m x F(x)=\frac{n}{x}*\frac{m}{x} F(x)=xnxm
反演得:
f ( x ) = Σ x ∣ d μ ( d x ) ∗ F ( d ) = Σ x ∣ d μ ( d x ) ∗ ( n d ) ∗ ( m d ) f(x)=\Sigma_{x|d}\mu(\frac{d}{x})*F(d)=\Sigma_{x|d}\mu(\frac{d}{x})*(\frac{n}{d})*(\frac{m}{d}) f(x)=Σxdμ(xd)F(d)=Σxdμ(xd)(dn)(dm)

以第二个样例为例:
s u m = f ( 1 ) + f ( 2 ) + f ( 3 ) + f ( 5 ) + f ( 7 ) sum=f(1)+f(2)+f(3)+f(5)+f(7) sum=f(1)+f(2)+f(3)+f(5)+f(7)
F ( n ) F(n) F(n)表示为
s u m = sum= sum=
F ( 1 ) [ μ ( 1 ) ] + F(1)[\mu(1)]+ F(1)[μ(1)]+
F ( 2 ) [ μ ( 1 ) + μ ( 2 ) ] + F(2)[\mu(1)+\mu(2)]+ F(2)[μ(1)+μ(2)]+
F ( 3 ) [ μ ( 1 ) + μ ( 3 ) ] + F(3)[\mu(1)+\mu(3)]+ F(3)[μ(1)+μ(3)]+
F ( 4 ) [ μ ( 1 ) + μ ( 2 ) + μ ( 4 ) ] + F(4)[\mu(1)+\mu(2)+\mu(4)]+ F(4)[μ(1)+μ(2)+μ(4)]+
F ( 5 ) [ μ ( 1 ) + μ ( 5 ) ] + F(5)[\mu(1)+\mu(5)]+ F(5)[μ(1)+μ(5)]+
F ( 6 ) [ μ ( 1 ) + μ ( 2 ) + μ ( 3 ) + μ ( 6 ) ] + F(6)[\mu(1)+\mu(2)+\mu(3)+\mu(6)]+ F(6)[μ(1)+μ(2)+μ(3)+μ(6)]+
F ( 7 ) [ μ ( 1 ) + μ ( 7 ) ] + F(7)[\mu(1)+\mu(7)]+ F(7)[μ(1)+μ(7)]+
F ( 8 ) [ μ ( 1 ) + μ ( 2 ) + μ ( 4 ) + μ ( 8 ) ] + F(8)[\mu(1)+\mu(2)+\mu(4)+\mu(8)]+ F(8)[μ(1)+μ(2)+μ(4)+μ(8)]+
F ( 9 ) [ μ ( 1 ) + μ ( 3 ) + μ ( 9 ) ] + F(9)[\mu(1)+\mu(3)+\mu(9)]+ F(9)[μ(1)+μ(3)+μ(9)]+
F ( 10 ) [ μ ( 1 ) + μ ( 2 ) + μ ( 5 ) + μ ( 10 ) ] F(10)[\mu(1)+\mu(2)+\mu(5)+\mu(10)] F(10)[μ(1)+μ(2)+μ(5)+μ(10)]
得:
s u m = Σ d = 1 m i n ( n , m ) ( n d ) ( m d ) Σ x ∣ d μ ( x ) sum=\Sigma_{d=1}^{min(n,m)}(\frac{n}{d})(\frac{m}{d})\Sigma_{x|d}\mu(x) sum=Σd=1min(n,m)(dn)(dm)Σxdμ(x)

所以用 n u m [ i ] num[i] num[i]数组存 ( a , b ) (a,b) (a,b)的对数,因为 2 19 = 524288 &gt; 5 e 5 2^{19}=524288&gt;5e5 219=524288>5e5所以素因子个数不会超过19个,数组 n u m num num开为二维数组,令 n u m [ i ] [ j ] num[i][j] num[i][j]表示素因子数量小于等于 j j j个的前 i i i项和

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <cmath>

using namespace std;
#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) x < y ? x : y
#define MAX(x,y) x > y ? x : y
typedef long long ll;
const int maxn = 5e5;
const double INF = 0x3f3f3f3f;
const int MOD = 1e9+7;


int prime[maxn+10],mu[maxn+10],tot = 0;
int cnt[maxn+10],num[maxn+10][22];
bool vis[maxn+10];
void Mobius(){
    me(vis,false);
    mu[1] = 1;
    for(int i = 2; i <= maxn; ++i){
        if(!vis[i]) prime[++tot] = i,mu[i] = -1,cnt[i] = 1;
        for(int j = 1; j <= tot & i*prime[j] <= maxn; ++j){
            vis[i*prime[j]] = true;
            cnt[i*prime[j]] = cnt[i]+1;
            if(i%prime[j] == 0){
                mu[i*prime[j]] = 0;
                break;
            }
            mu[i*prime[j]] = -mu[i];
        }
    }
    for(int i = 1; i <= maxn; ++i){ //
        for(int j = i; j <= maxn; j+=i){
            num[j][cnt[i]] += mu[j/i];
        }
    }
    for(int i = 1; i <= maxn; ++i){
        for(int j = 0; j <= 20;++j){
            num[i][j] += num[i][j-1];
        }
    }
    for(int i = 1; i <= maxn; ++i){
        for(int j = 0; j <= 20; ++j){
            num[i][j] += num[i-1][j];
        }
    }
}

int main(){
    int t;
    cin>>t;
    Mobius();
    while(t--){
        int n,m,p;
        scanf("%d%d%d",&n,&m,&p);
        if(p > 19) p = 19;
        ll sum = 0;
        for(int l = 1,r; l <= min(n,m); l = r+ 1){
            r = min(n/(n/l),m/(m/l));
            sum += (ll)(n/l)*(m/l)*(num[r][p]-num[l-1][p]);
        }
        printf("%lld\n",sum);
    }
    return 0;
}

/*


*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值