题意:统计[l,r]中与m互素的数的个数
解法:1.求前缀[1,r]中与m互素的个数
2.求反面——不互素的个数,再将m分解质因子,转化为整除问题
(a,m)!=1,则m至少有一个质因子整除a。ans=
|A1∪A2∪...∪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);
}
}