hdu 4135 Co-prime(容斥原理)

Co-prime

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


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 <= 10 15) and (1 <=N <= 10 9).
 

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

给定两个数 a b和一个数 n  求[a,b]范围内与n互素的数的个数

如果一个个的判断是否互素 会超时

我们考虑相反的问题  求不与n互素的个数  即这些数与n有相同的数因子  

考虑n所有的素因子pi  求在[a,b]范围内有多少个能被pi整除 

如果全部把这些数全都减去 会减多了 因为一个数会是几个素因子的公倍数  

所以用容斥原理 

用欧拉函数处理出 n所有的素因子 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

#define eps 1e-8
#define op operator
#define MOD  10009
#define MAXN  100100
#define INF 0x7fffffff

#define FOR(i,a,b)  for(int i=a;i<=b;i++)
#define FOV(i,a,b)  for(int i=a;i>=b;i--)
#define REP(i,a,b)  for(int i=a;i<b;i++)
#define REV(i,a,b)  for(int i=a-1;i>=b;i--)
#define MEM(a,x)    memset(a,x,sizeof a)
#define ll __int64

using namespace std;

ll pri[1000000];
int num;

void phi(ll n)
{
    num=0;
    for(int i=2;i*i<=n;i++)
    {
        if(n&&n%i==0)
        {
            while(n%i==0)
            {
                n/=i;
            }
            pri[num++]=i;
        }
    }
    if(n>1)  pri[num++]=n;
}

ll ans(ll n,int m)
{
    ll res=0;
    ll y=(ll)1<<m;//用二进制来1,0来表示第几个素因子是否被用到,如m=3,三个因子是2,3,5,则i=3时二进制是011,表示第2、3个因子被用到 
    for(int i=1;i<y;i++)
    {
        int flag=0;
        ll tmp=1;
        for(int j=0;j<m;j++)
        {
            if(i&(ll)(1<<j))//判断第几个因子目前被用到
            {
                flag++;//记录用的因子个数
                tmp*=pri[j];
            }
        }
        if(flag&1)
            res+=n/tmp;
        else res-=n/tmp;
    }
    return res;
}

int main()
{
//freopen("ceshi.txt","r",stdin);
    int tc;
    scanf("%d",&tc);
    int cs=1;
    while(tc--)
    {
        ll a,b,n;
        scanf("%I64d%I64d%I64d",&a,&b,&n);
        phi(n);
//        for(int i=0;i<num;i++)
//            cout<<pri[i]<<endl;

        printf("Case #%d: %I64d\n",cs++,(b-ans(b,num))-(a-1-ans(a-1,num)));
    }
    return 0;
}




  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值