HDU-4135 Co-prime (容斥定理求区间互质个数)

Co-prime
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10291 Accepted Submission(s): 4011

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}.

Source
The Third Lebanese Collegiate Programming Contest

Recommend
lcy | We have carefully selected several similar problems for you: 1434 3460 1502 4136 4137

题意:

给出a, b, n, 求[a,b]中与n互质的元素个数

思路分析:

乍一看和欧拉函数很像,但是又有点不同。欧拉函数phi[i] = n表示[1,i]中与i互质的个数为n.
因此得想别的办法。
我们要求[a,b]中与n互质的元素个数可以转化成f([a,b]) = f([1,b]) - f([1,a-1]).
那么如何求[1,X]中与n互质的元素个数呢?
我们可以逆着想,求与n不互质的元素个数,这个不互质的元素其实就是n的素因子倍数。假设n的素因子有2,3. 那么2的倍数有[n/2]个,3的倍数有[n/3]个。2和3的倍数里面关于6的倍数被重复加了,需要减掉。这个6就是2,3的最小公倍数。因此不互质元素个数为 [n/2] + [n/3] - [n/lcm(2,3)]。以上就是容斥定理,不再多介绍了。容斥定理遵循一个原则:奇加偶减。

通过容斥定理求出[1,X]不互质的个数,用X减去,就可以得到[1,X]的互质个数了。

下面上代码

#include <iostream>
#include <cstring> 
#include <cmath>
#include <map>
#define ll long long
using namespace std; 

const int N = 100000;
ll prime[N];	
int t;
int vis[N];
ll T, n, a, b;
ll factor[100];	//存放素因子 
ll cnt;	 
ll tmp1, tmp2, ans;	//tmp1为[1,a-1]中与n不互质的个数,tmp2为[1,b]中与n不互质的个数 

ll gcd(ll a,ll b){
    return b == 0?a:gcd(b,a%b);
}

void isPrime()	//打素数表 
{
    t=0;
    memset(vis,0,sizeof(vis));
    memset(prime,0,sizeof(prime));
    for(ll i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime[t++]=i;
            for(ll j=i*i;j<N;j+=i)
                vis[j]=1;
        }
    }
}


void splitPrime(ll x)	//分解素因子 
{
    cnt=0;
    ll t=x;
    for(int i=0;prime[i]<=t/prime[i];i++)
    {
        while(t%prime[i]==0)
        {
            factor[cnt]=prime[i];
            while(t%prime[i]==0)
            {
                t/=prime[i];
            }
            cnt++;
        }
    }
    if(t!=1)
    {
        factor[cnt]=t;
        cnt++;
    }
}


void dfs(ll cur, ll lcm, ll id)	//求出[1,a-1]和[1,b]与n非互质的个数 
{
	lcm = factor[cur]*lcm/gcd(lcm,factor[cur]);
//	cout<<cur<<" "<<lcm<<endl;
	if(id&1) tmp1 += (a-1)/lcm, tmp2 += b/lcm;	//读取id最后一个二进制位,若为1,则id为奇数。 
	else tmp1 -= (a-1)/lcm, tmp2 -= b/lcm;
	for(int i = cur+1;i < cnt;i++)
	dfs(i, lcm, id+1);
}

int main()
{
	isPrime();
	cin>>T;
	int ii = 1;
	while(T--)
	{
		tmp1 = 0, tmp2 = 0, ans = 0;
		cin>>a>>b>>n;
		splitPrime(n);
		for(int i = 0;i < cnt;i++)
		dfs(i,factor[i],1);
		ans = (b-tmp2) - (a-1-tmp1);	//[1,b]与n互素的个数 - [1,a-1]与n互素的个数就是[a,b]与n互素的个数 
		printf("Case #%d: %lld\n",ii,ans);
		ii++;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值