hdu1695 综合数论 欧拉函数 分解质因子 容斥原理 打印素数表 各种模板

题目大意: 

给你a, b, c, d, k; 找出这样的一队 x, y, 使得 gcd(x , y) = k, 并且x ∈[1, b], y ∈ [1, d], 问有多少对符合要求的(x, y)。 


思路: gcd(x, y) == k 说明x,y都能被k整除, 但是能被k整除的未必gcd=k , 必须还要满足互质关系. 问题就转化为了求1~a/k 和 1~b/k间互质对数的问题可以把a设置为小的那个数, 那么以y>x来保持唯一性(题目要求, 比如[1,3] =[3,1] ) 接下来份两种情况: 

  1. y <= a , 那么对数就是 1~a的欧拉函数的累计和(容易想到) 
  2. y >= a , 这个时候欧拉函数不能用了,怎么做?  可以用容斥原理,把y与1~a互质对数问题转换为y的质数因子在1~a范围内能整除的个数(质数分解和容斥关系),   
#include <iostream>  
#include <stdio.h>  
#include <memory.h>  
#include<math.h>  
#include <vector>  
using namespace std;  
  
const int N = 100005;  
typedef long long LL;  
#define maxn 100005  
LL phi[N];  
vector<LL> link[N];  
int vis[1000000+5],c;    
LL prime[79000];    
void get_prime()  //打印素数表模板  
{    
    int i,j,n,m;    
    c=0;    
    n=1000000;    
    m=(int)sqrt(n+0.5);    
    memset(vis,0,sizeof(vis));    
    for(i=2;i<=m;i++)     
        if(!vis[i])    
        {    
            for(j=i*i;j<=n;j+=i)    
                vis[j]=1;    
        }    
    for(i=2;i<=n;i++) if(!vis[i])    
        prime[c++]=i;    
}    
  
  
void get_PHI()  //模板  得到1->n-1 与n互质的数的个数  存入phi[n]  (欧拉函数打表)
{    
    int i,j;    
    for (i = 1; i <= maxn; i++) phi[i] = i;    
    for (i = 2; i <= maxn; i += 2) phi[i] /= 2;    
    for (i = 3; i <= maxn; i += 2) if(phi[i] == i)    
    {    
        for (j = i; j <= maxn; j += i)    
            phi[j] = phi[j] / i * (i - 1);    
    }    
}  

int ouler(int x)  //欧拉函数:判断得到1->n-1 与n互质的数的个数 (不打表)
{  
    int i,j,k=1;  
    int m=x;  
    for(i=2;i<=m;i++)  
    {  
        if(m%i==0)  
        {  
            k=k*(i-1);  
            while(m%i==0)  
            {  
                m=m/i;  
                k*=i;  
            }  
            k/=i;  
        }  
    }  
    return k;  
} 


void init()     //求每一个数的质因数,vector储存    
{  
    LL i, j, k;  
    for(i = 1; i < N; i++)//求n的质因数  也是模板  
    {  
        k = i;  
        for(j = 0; prime[j]*prime[j] <= k; j++)  
        {  
            if(k%prime[j] == 0)  
            {  
                link[i].push_back(prime[j]);  
                while(k%prime[j] == 0)  
                    k /= prime[j];  
            }  
            if(k == 1) break;  
        }  
        if(k > 1) link[i].push_back(k);  
    }  
}  
  
LL make_ans(LL num,LL n)//1到num中的所有数与n的m个质因子不互质的数的个数 注意是不互质哦    容斥原理  
{    
    LL ans=0,tmp,i,j,flag;    
    for(i=1;i<(LL)(1<<link[n].size());i++)    
    { //用二进制来1,0来表示第几个素因子是否被用到,如m=3,三个因子是2,3,5,则i=3时二进制是011,表示第2、3个因子被用到      
        tmp=1,flag=0;    
        for(j=0;j<link[n].size();j++)     
            if(i&((LL)(1<<j)))//判断第几个因子目前被用到     
                flag++,tmp*=link[n][j];//第j个质因子link[n][j]  
        if(flag&1)//容斥原理,奇加偶减      
            ans+=num/tmp;    
        else    
            ans-=num/tmp;    
    }    
    return ans;    
}    
  
  
int main()  
{  
    LL i, a, b, c, d, k, sum, t, zz = 1;//longlong型的数据 可以用%I64d 来输入输出  
    get_prime();  
    get_PHI();  
    init();  
    scanf("%I64d", &t);  
    while(t--)  
    {  
        scanf("%I64d %I64d %I64d %I64d %I64d", &a, &b, &c, &d, &k);  
        if(k == 0 || k > b || k > d)  
        {  
            printf("Case %I64d: 0\n", zz++);  
            continue;  
        }  
        if(b > d) swap(b, d);//保持d较大  
        b /= k;  
        d /= k;  
        sum = 0;  
        for(i = 1; i <= b; i++)  
        {  
            sum += phi[i];  
        }  
        for(i = b+1; i <= d; i++)  
        {  
            sum += b - make_ans(b, i);  
        }  
        printf("Case %I64d: %I64d\n", zz++, sum);  
    }  
  
    return 0;  
}  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值