hdu4135 Co-prime(互素统计)

题意:统计[l,r]中与m互素的数的个数
解法:1.求前缀[1,r]中与m互素的个数
2.求反面——不互素的个数,再将m分解质因子,转化为整除问题
(a,m)!=1,则m至少有一个质因子整除a。ans= |A1A2...Ak| Ai 为[1,r]中m的第i个质因子的倍数集合
复杂度:O(m*logm),与区间大小无关

拓展:
1.统计a[1,2…n]中与m互素的数的个数(a[i]<=A)
1.1预处理[1,A]中所有数在a数组因子中出现的次数beinum
1.2在打星处将a/tmp改为beinum[tmp]即可

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#define lowbit(x) x&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
#define rad 10000

const ll maxp= 100000;

int t;
ll a,b,n,ans;
bool not_prime[maxp];
vector<ll> prime,factor;

void make_prime(){
    memset(not_prime,0,sizeof(not_prime));
    prime.clear();
    not_prime[0]=not_prime[1]=1;
    for(ll i=2;i<maxp;i++){
        if(!not_prime[i]) prime.push_back(i);
        for(ll j=0;j<prime.size(),i*prime[j]<maxp;j++){
            not_prime[i*prime[j]]=1;
            if(!(i%prime[j])) break;
        }
    }
}

void divided(ll x){
    factor.clear();
    for(ll i=0;i<prime.size();i++){
        if(prime[i]*prime[i]>x) break;
        if(x%prime[i]==0){
            factor.push_back(prime[i]);
            while(x%prime[i]==0) x/=prime[i];
        }
    }
    if(x!=1) factor.push_back(x);
}

ll cal_sunum(ll a,ll n){//统计[1,a]中与n互素的数的个数
    if(!a) return 0;
    ll len,tmp,tmpnum,ans;
    len=factor.size(),ans=0;
    //计算[1,a]中不与n互素的数的个数
    for(ll i=1;i<(1<<len);i++){
        tmp=1,tmpnum=0;
        for(ll j=0;(1<<j)<=i;j++){
            if((1<<j)&i){
                tmp*=factor[j];
                if(tmpnum) tmpnum=0;
                else tmpnum=1;
            }
        }
        if(tmpnum) ans+=(a/tmp);//***
        else ans-=(a/tmp);//***
    }
    return a-ans;
}

int main(){
    //freopen("a.txt","r",stdin);
    scanf("%d",&t);
    make_prime();
    for(int cas=1;cas<=t;cas++){
        scanf("%lld%lld%lld",&a,&b,&n);
        divided(n);
        ans=cal_sunum(b,n)-cal_sunum(a-1,n);
        printf("Case #%d: %lld\n",cas,ans);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值