您的位置:首页 > 产品设计 > UI/UE

hdu 4746 Mophues 莫比乌斯反演

2015-07-31 16:39 513 查看


Mophues

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 327670/327670 K (Java/Others)

Total Submission(s): 910 Accepted Submission(s): 345



Problem Description

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×105. 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




Source

2013 ACM/ICPC Asia Regional Hangzhou Online

题目:求1<=a<=n,1<=b<=m ,gcd(a,b) 的质因数个数 <= p的a,b的组合数
莫比乌斯反演:
http://blog.csdn.net/acdreamers/article/details/12871643 详情看这篇博客。写得挺详细。赞~~

如果定义最大公约数为x,
定义函数F(x) = (n/x)*(m/x)
显然最大公约数为x的a,b组合数包含在F(x)中了,但是F(x)还包括了gcd = 2*x,3*x,......,y*x的情况,需要把它们删除
实际是,我们要求得是n/x,m/x的组合中有几组是互质的情况。如果用容斥的方法,我们需要删除包含了质因数2,3,5.。。。。的情况,即减去(n/x)/2*(m/x)/2这种情况
然后因为如10,这样包含两个质因数的情况呗删除两次,又需要加回来。又要加上m/x/10 * n/x/10。
对于每个因数(不只是质因数),会发现只需要加一次,或者减一次即可。然后就是莫比乌斯函数啦。
定义Y(x)为最大公约数为x的组合数,u(x)为x的莫比乌斯函数,那么
Y(x) = F(x)*u(1) + F(x*2)*u(2) + F(x*3)+ u(3) + ............ + F(x*n)*u(n)
枚举x = 1 to n
可以算出没给F(x)的系数,再通过系数*F(x)就能得到答案了。 最后通过分块加速,可以做到n^1/2的优化
-----------------------------------------参考博客写了,我就不啰嗦了

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define maxn 500007
//记录质因数个数,
int prinum[maxn];
//每个数的u函数
int fu[maxn];
//记录是否为质数
int check[maxn];
//记录u函数的前缀和,第二位表示质因数个数
int usnum[maxn][20];
int call(int j,int i){
    if(j % i != 0) return 0;
    return call(j/i,i)+1;
}
void init(){
    memset(check,0,sizeof(check));
    memset(prinum,0,sizeof(prinum));
    memset(usnum,0,sizeof(usnum));
    memset(fu,0,sizeof(fu));
    //筛出质数,并计算每个数的质因数个数
    for(int i = 2;i < maxn; i++){
        if(check[i]) continue;
        for(int j = i;j < maxn; j += i){
            check[j] = 1;
            if(j % (i*i) == 0) fu[j] = -1;
            prinum[j] += call(j,i);
            if(fu[j] != -1) fu[j]++;
        }
    }
    for(int i = 1;i < maxn; i++)
        if(fu[i] == -1)
            fu[i] = 0;
        else
            fu[i] = 1 - 2*(fu[i]&1);
    //如筛素数法,计算每个数的U值之和
    for(int i = 1;i < maxn; i++){
        for(int j = i;j < maxn; j+=i){
            usnum[j][prinum[i]] += fu[j/i];
        }
    }

    //计算u的前缀和
    for(int i = 1;i < maxn; i++){
        for(int j = 1;j < 20; j++)
            usnum[i][j] += usnum[i][j-1];
        for(int j = 0;j < 20; j++)
            usnum[i][j] += usnum[i-1][j];
    }
}

int main(){
    init();
    int t,n,m,p;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&p);
        if(n > m) swap(n,m);
        long long ans = 0;
        p = min(p,19);
        int j;
        if(p > 19)
            ans = 1ll*n*m;
        else
            for(int i = 1;i <= n; i = j + 1){
                j = min(n/(n/i),m/(m/i));
                ans += (usnum[j][p]-usnum[i-1][p])*1ll*(n/i)*(m/i);
            }
        printf("%I64d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: