求区间(a,b)中与n的互质数

给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。
两个数互质当且仅当他们除了1之外没有其他的公共因子或者他们最大的公共因子是1。1和任何数是互素的

假设m=12,n=30.

第一步:求出n的质因子:2,3,5;

第二步:(1,m)中是n的因子的倍数当然就不互质了(2,4,6,8,10)->n/2 6个,(3,6,9,12)->n/3 4个,(5,10)->n/5 2个。

如果是粗心的同学就把它们全部加起来就是:6+4+2=12个了,那你就大错特错了,里面明显出现了重复的,我们现在要处理的就是如何去掉那些重复的了!

第三步:这里就需要用到容斥原理了,公式就是:n/2+n/3+n/5-n/(2*3)-n/(2*5)-n/(3*5)+n/(2*3*5).

第四步:我们该如何实现呢?我在网上看到有几种实现方法:dfs(深搜),队列数组,位运算三种方法都可以!上述公式有一个特点:n除以奇数个数相乘的时候是加,n除以偶数个数相乘的时候是减。我这里就写下用队列数组如何实现吧:我们可以把第一个元素设为-1然后具体看代码如何实现吧!

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include<algorithm>
using namespace std;

typedef long long ll;
const int N=100005;
vector<ll> v;

ll re(ll x){
  ll cnt=0;
  ll u=1;
  ll ans=0;
  for(ll i=1;i<(1ll<<v.size());i++){
      u=1;
      cnt=0;
  for(int j=0;j<v.size();j++){
      if((1ll<<j)&i){
          cnt++;
          u*=v[j];
      }
  }
  if(cnt&1ll){
      ans+=x/u;
  }else{
    ans-=x/u;
  }
  }
 return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll a,b,n;
        bool f=0;
        ll cnt=0;
        v.clear();
        scanf("%lld%lld%lld",&a,&b,&n);

        for(ll i=2;i*i<=n;i++){
             if(n%i==0){
                v.push_back(i);
                while(n%i==0){
                   n/=i;
                }
             }
        }
        if(n!=1){
          v.push_back(n);
        }       
        //cout<<re(b)<<endl;
        ll ans=b-re(b)-(a-re(a-1)-1);
        cout<<ans<<endl;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值