hdu 4135 Co-prime(容互原理 DFS+位运算求解)

来源:互联网 发布:mac系统安装软件 编辑:程序博客网 时间:2024/05/21 07:57

hdu 4135 Co-prime

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

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: 1796 1434 3460 1502 4136

题解

给出区间【A,B】和数字n 求解 与n互质的数的个数(即与n没有公约数的数的个数),1 <= A <= B <= 10^15 显然不能用暴力求解,所以用到容斥
下面我们一步一步来进行分析:
1 求【A,B】区间与k互质的个数转化成求解【1,B】区间中与n互斥的个数减去【1,A-1】中与k互斥的个数 (A-1 是因为要把A算进去)
2. 接下来问题转化成为求1到一个数n区间内的与k互质的数的个数,那么思路再转换,求互质,可以先求不互质,然后一减不就得到了么?
3. 那么如何求不互质的呢,可以先将k 进行素因子分解,用然后再区间【1,n】 中 ,用 n/素因子 可以得到对应这个素因子的区间内的不互质的个数,然后每个都求一遍,但会有重复的。
下面举个例子:
【1,10】 求关于12的
12 的素因子有 2,3
【1,10】 10/2=5 有5个(2,4,6,8,10)
【1,10】 10 /3=3 有3个(3,6,9)
但是会发现 6重复了
【1,10】 10/(2*3)=1 个-最后结果是 5+3-1=7 个 然后互质的有10 -7=3 个
4. 所以这里有个规律(奇加偶减) 10/2+10/3-10/(2*3)

至于如何求算 有的dfs 和 位运算求解两种把吧
1. 位运算:
用二进制1,0 来表示第几个素因子是否会被用到 如果你求的素因子个数为3 则 i=3时二进制位011 表示第 2 3 个因子被用到
i=1 001 表示只有第3个数被用到
AC1:

#include<bits/stdc++.h>using namespace std;typedef long long ll;ll Sovle(ll n,ll r){    vector<ll> p;  // 存放素因子    for(ll i=2;i*i<=n;i++)    {        if(n%i==0)        {            p.push_back(i);    // 若能整除加入            while(n%i==0) n/=i;   //循环除尽        }    }    if(n>1) p.push_back(n);      ll ans=0;    for(ll temp =1;temp<(1<<p.size());temp++)   //1左移素因子个数位    {        ll multi=1,bits=0;   // utli 存放要求的约数 bits是用到的素因子的个数        for(ll i=0;i<p.size();i++)  //循环判断每一位是否用到        {            if(temp&(1<<i))     //用到            {                ++bits;      //用到的个数+1                multi*=p[i];  // 乘到约数中             }         }         ll cur=r/multi;     // 求解个数         if(bits&1) ans+=cur;  // 奇加偶解         else ans-=cur;    }    return r-ans;}int main(){    int T,n,cases=0;    ll A,B;    cin>>T;    while(T--)    {        cin>>A>>B>>n;        ll res,ans;        ans=Sovle(n,A-1);        res=Sovle(n,B);        printf("Case #%d: %lld\n",++cases,res-ans);    }    return 0;}

下面是bfs:
AC2:

#include<bits/stdc++.h>using namespace std;typedef long long ll;vector<ll> fac;void GetFactor(int n){    fac.clear();    for(ll i=2;i*i<=n;i++)    {        if(n%i==0)        {            fac.push_back(i);            while(n%i==0) n/=i;        }    }    if(n>1) fac.push_back(n);}ll ans;void dfs(int cur,int num,ll mul, ll A){    if(cur==fac.size())    {        if(num&1) ans-=A/mul;        else ans+=A/mul;        return;    }    dfs(cur+1,num,mul,A);    dfs(cur+1,num+1,mul*fac[cur],A);}int main(){    int T,n,cases=0;    ll A,B;    cin>>T;    while(T--)    {        cin>>A>>B>>n;        GetFactor(n);        ans=0;        dfs(0,0,1,B);        ll res=ans;        ans=0;        dfs(0,0,1,A-1);        printf("Case #%d: %lld\n",++cases,res-ans);    }    return 0;}
原创粉丝点击