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

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值