hdu 4135 Co-prime(分解质因数+容斥定理)

本文介绍了一种计算指定区间内与给定数互质整数个数的有效算法。通过将问题转化为计算与该数不互质的数的个数,利用质因数分解和数学原理,实现了快速准确的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目】

Co-prime

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8210    Accepted Submission(s): 3274


 

Problem Description

Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.

 

 

Input

The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 1015) and (1 <=N <= 109).

 

 

Output

For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.

 

 

Sample Input

 

2

1 10 2

3 15 5

 

Sample Output

 

Case #1: 5

Case #2: 10

 

Hint

In the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.

【题意】

给定 t 组数据,给定区间 [a,b] 和 k,输出区间 [a,b] 中与 k 互质的数的个数。

【思路】

首先,把问题转化成[1,b]中与k互质的个数-[1,a]中与k互质的个数。要求[1,n]中与k互质的数有多少,我们可以先求[1,n]中与k不互质的数有多少。

这点求法再拉出来细说:先把 k 分解质因数,存在一个数组中。

举个例子,比如 k 的质因子有 2,3,5。那么2、3、5的倍数都不和 k 互质,另外可能有重复的地方,比如6既是2的倍数又是3的倍数,前面用 k/2 + k/3 的时候多减了,这个时候要加上 k / (2*3)。同理,10,15这一类数都应该加上。但是还有类似于30这样的数,它是2,3,5的倍数,减的时候又多减了。

然后我们会发现,出现奇数个数就用加法,偶数个数用减法。

最后的式子是这样的:k / 2 + k / 3 + k / 5 - k / (2 * 3) - k / (3 * 5) - k / (2 * 5) + k / (2 * 3 * 5)。

【代码】

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define Pi acos(-1)
#define eps 1e-8
using namespace std;
typedef long long int ll;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
ll fac[1005],num,ansa,ansb,a,b,k;
void init()
{
    ansa=0,ansb=0,num=0;
    scanf("%lld%lld%lld",&a,&b,&k);
    a--;
    for(ll i=2;i*i<=k;i++)
    {
        if(k%i==0) fac[num++]=i;
        while(k%i==0) k/=i;
    }
    if(k>1) fac[num++]=k;
}
ll gcd(ll a, ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a, ll b){return a*b/gcd(a, b);}
void dfs(ll pre,ll now,ll step)
{
    if(step>num) return;
    ll Lcm=lcm(now,fac[pre]);
    if(step&1)
    {
        ansa+=a/Lcm;
        ansb+=b/Lcm;
    }
    else
    {
        ansa-=a/Lcm;
        ansb-=b/Lcm;
    }
    for(ll i=pre+1;i<num;i++)
        dfs(i,Lcm,step+1);
}
main()
{
    int t; scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        init();
        for(int j=0;j<num;j++)
            dfs(j,fac[j],1);
        ll ans=(b-a)-(ansb-ansa);
        printf("Case #%d: %lld\n",i,ans);
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值