首页 > 代码库 > HDU 1695 GCD 欧拉函数+容斥原理+质因数分解

HDU 1695 GCD 欧拉函数+容斥原理+质因数分解

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695

题意:在[a,b]中的x,在[c,d]中的y,求x与y的最大公约数为k的组合有多少。(a=1, a <= b <= 100000, c=1, c <= d <= 100000, 0 <= k <= 100000)

思路:因为x与y的最大公约数为k,所以xx=x/k与yy=y/k一定互质。要从a/k和b/k之中选择互质的数,枚举1~b/k,当选择的yy小于等于a/k时,可以选择的xx数为Euler(yy),当yy大于a/k时,就要用容斥原理来找到yy的质因数,在a/k范围内找到与yy互质的数。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <ctype.h>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#define PI acos(-1.0)
#define maxn 1<<20
#define INF 0x7fffffff
#define eps 1e-8
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
LL ans=0;
LL S=0;
LL sum2;
LL euler[100050];
void init()
{
    memset(euler,0,sizeof(euler));
    euler[1] = 1;
    for(int i = 2; i <= 100000; i++)
        if(!euler[i])
            for(int j = i; j <= 100000; j += i)
            {
                if(!euler[j])
                    euler[j] = j;
                euler[j] = euler[j]/i*(i-1);
            }
}
void factor(int n,int a[maxn],int b[maxn],LL &tt)
{
    int temp,i,now;
    temp=(int)((double)sqrt(n)+1);
    tt=0;
    now=n;
    for(i=2; i<=temp; i++)
    {
        if(now%i==0)
        {
            a[++tt]=i;
            b[tt]=0;
            while(now%i==0)
            {
                ++b[tt];
                now/=i;
            }
        }
    }
    if(now!=1)
    {
        a[++tt]=now;
        b[tt]=1;
    }
}
int dfs(int aa[],int pos,int res,int sum,int b,int tot)//res乘积,sum乘数的个数
{
    if(pos+1<=tot)
        dfs(aa,pos+1,res,sum,b,tot);
    sum++;
    res*=aa[pos];
    if(sum%2)
        sum2+=b/res;
    else
        sum2-=b/res;
    if(pos+1<=tot)
        dfs(aa,pos+1,res,sum,b,tot);
    return 0;
}
int main()
{
    int T,tt=0,aa[40],bb[40];
    init();
    while(~scanf("%d",&T))
    {
        tt=0;
        while(T--)
        {
            tt++;
            int a,b,c,d,k;
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
            printf("Case %d: ",tt);
            if(k==0)
            {
                printf("0\n");
                continue;
            }
            if(d<b)
                swap(b,d);
            b/=k;
            d/=k;
            if(!b)
            {
                printf("0\n");
                continue;
            }
            ans=0;
            for(int i=1; i<=b; i++)
                ans+=euler[i];
            for(int i=b+1; i<=d; i++)
            {
                sum2=0;
                factor(i,aa,bb,S);
                dfs(aa,1,1,0,b,S);
                ans+=b-sum2;
            }
            printf("%I64d\n",ans);
        }
    }
    return 0;
}