GCD HDU - 1695 求区间内gcd=k的对数 容斥原理+欧拉phi函数

题目链接:https://vjudge.net/problem/HDU-1695
转自:https://blog.csdn.net/qq_41129854/article/details/84768431
题意:求1~ b与1 ~ d之间gcd=k的数对数。两数互换视为同一组。
思路:求(1,b)与(1,d)之间gcd=k的对数等于求区间1:(1,b/ k)与区间2:(1,d/ k)之间互素的数的个数。 可以用容斥原理求出区间1中与区间2中互素的对数( 一个数a除以b的商就是小于等于a内有多少个数是b的倍数 )。但注意要去重。,例如n=3,m=5,重复是(1,2)和(2,1),(1,3)和(3,1),(2,3)和(3,2),发现重复的就是(2,1),(3,1),(3,2),即2-n的各个数的欧拉函数和 ,这时候就可以用欧拉函数算出重复的部分。
由于phi[1]=1,因此需要额外修正。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int maxn=1e5+5;
long long phi[maxn];
void phi_table()//欧拉函数
{
    memset(phi,0,sizeof(phi));
    phi[1]=1;
    for(int i=2; i<=1e5; i++)
    {
        if(!phi[i])
        {
            for(int j=i; j<=1e5; j+=i)
            {
                if(!phi[j])
                {
                    phi[j]=j;
                }
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }
}
vector <long long >v;
void prime(long long n)//因数分解
{
    v.clear();
    for(long long i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            v.push_back(i);
            while(n%i==0)
                n/=i;
        }
        if(n==1)
            break;
    }
    if(n>1)
        v.push_back(n);
}
long long fg(long long n)//容斥原理求互素的对数
{
    long long sz=v.size();
    long long sum=0;
    for(long long i=1;i<(1<<sz);i++)
    {
        long long ans=1,cnt=0;
        for(long long j=0;j<sz;j++)
        {
            if(i&(1<<j))
            {
                ans*=v[j];
                cnt++;
            }
        }
        if(cnt%2==1)
        {
            sum=sum+n/ans;
        }
        else
            sum=sum-n/ans;
    }
    return n-sum;
}
int main()
{
    int T,kase=0;
    long long a,b,c,d,k;
    long long n,m;
    scanf("%d",&T);
    phi_table();
    while(T--)
    {
        scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
        printf("Case %d: ",++kase);
        if(k==0||k>b||k>d)
        {
            printf("0\n");
            continue;
        }
        n=b/k,m=d/k;
        if(n>m)
            swap(n,m);
        long long sum=1;//phi[1]=1的修正
        for(long long i=1;i<=n;i++)
        {
            prime(i);
            sum+=fg(m);
            sum-=phi[i];
        }
        printf("%lld\n",sum);
    }

    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值