【欧拉函数,莫比乌斯反演】

【普通版】首先是一道单纯的容斥题目(hdu4135):

求[a,b]内与n互质的数的个数,n<=10^9,a,b<=10^14.

可以先用容斥求出[a,b]与n不互质的数的个数,再相减。

#include<bits/stdc++.h> 
#define ll long long
using namespace std; 
int main (){
    int t,cnt=0;
    cin>>t;
    while(t--){
    	ll a,b,n;
    	scanf("%I64d%I64d%I64d",&a,&b,&n);
    	vector<int> v;
    	for(int 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);
    	ll s1=0,s2=0;
    	a--;
    	for(int i=1;i<(1<<v.size());++i){
    		ll s=1,p=0;
    		for(int j=0;j<v.size();++j){
    			if(i&(1<<j)){
    				s*=v[j];
    				p++;
    			}
    		}
    		if(p%2==1){
    			s1+=a/s;
    			s2+=b/s;
    		}
    		else{
    			s1-=a/s;
    			s2-=b/s;
    		}
    	}
    	printf("Case #%d: %I64d\n",++cnt,(b-s2)-(a-s1));
    }
    return 0;
}

【加强版】(hdu1695)在[1,b]中取一个数x,[1,d]中取一个数y,满足gcd(x,y)=k。求(x,y)的对数。bdk<=10^5,ac=1

这题可以有三种做法:[直接对质因子容斥]或者[欧拉函数优化+容斥]或者[莫比乌斯反演]。最后一种效率最高。

用欧拉函数做的那种方法可以参考上一个题解。由于k是定值所以不用枚举了。gcd(x/k,y/k)=1.

直接对质因子容斥

#include <cstdio>  
#include <cstring>  
#include <vector>  
#include <algorithm>  
using namespace std; 
#define N 100005  
typedef long long ll; 
vector<int> x[N]; 
bool is[N]; 
void prime(){  
    memset(is,false,sizeof(is)); 
    for(int i=0;i<N;i++) x[i].clear(); 
    for(int j=2;j<N;j+=2) x[j].push_back(2); 
    for(int i=3;i<N;i+=2) 
        if(!is[i]){  
            for(int j=i;j<N;j+=i){  
                is[j]=true; 
                x[j].push_back(i); 
            }  
        }  
}  
int work(int u,int s,int w){  
    int cnt=0,v=1; 
    for(int i=0;i<x[w].size();i++){  
        if((1<<i)& s){  
            cnt++; 
            v*=x[w][i]; 
        }  
    }  
    int all=u/v; 
    if(cnt%2==0)return -all; 
    else return all; 
}  
int main(){  
    prime(); 
    int T,a,b,c,d,k; 
    scanf("%d",&T); 
    for(int cas=1;cas<=T;cas++){  
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 
        if(k==0){  
            printf("Case %d: 0\n",cas); 
            continue; 
        }  
        b /= k,d /= k; 
        if(b>d){ a=b;b=d;d=a;}  
        long long ans=0; 
        for(int i=1;i<=d;i++){  
            k=min(i,b); 
            ans+=k; 
            for(int j=1;j<(1<<x[i].size());j++) 
                ans-=work(k,j,i); 
        }  
        printf("Case %d: %I64d\n",cas,ans); 
    }  
    return 0; 
}
【欧拉函数优化+容斥】

#include<bits/stdc++.h>
using namespace std;
const int Max=100005;
__int64 elur[Max];//存放每个数的欧拉函数值
vector<int> p[Max];//存放数的素因子
void init(){//筛选法得到数的素因子及每个数的欧拉函数值
    elur[1]=1;
    for(int i=2;i<Max;i++){
        if(!elur[i]){
            for(int j=i;j<Max;j+=i){
                if(!elur[j])
                    elur[j]=j;
                elur[j]=elur[j]*(i-1)/i;
                p[j].push_back(i);
            }
        }
        elur[i]+=elur[i-1]; //进行累加(法里数列长度)
    }
}
int main(){
    int t,a,b,c,d,k;
    init();
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++){
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        printf("Case %d: ",ca);
        if(k==0){
            printf("0\n");
            continue;
        }
        if(b>d)
            swap(b,d);
        b/=k;  d/=k;
        __int64 ans=elur[b];
        for(int i=b+1;i<=d;i++){
        	ans+=b;
        	for(int j=1;j<(1<<p[i].size());++j){ //求不大于b的数中,与i不互质的数的个数
				int s=1,w=0;   
				for(int k=0;k<p[i].size();++k){
					if(j&(1<<k)){
						s*=p[i][k];
						w++;
					}
				}
				if(w%2==1)
					ans-=b/s;
				else
					ans+=b/s;
        	}
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
【莫比乌斯反演】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000000;
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Moblus(){
    memset(check,false,sizeof(check));
    mu[1]=1;
    int tot=0;
    for(int i=2;i<=MAXN;i++){
        if( !check[i] ){
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>MAXN)break;
            check[i*prime[j]]=true;
            if( i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            else{
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
}
int main(){
    int T;
    int a,b,c,d,k;
    Moblus();
    scanf("%d",&T);
    int iCase=0;
    while(T--){
        iCase++;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if(k==0){
            printf("Case %d: 0\n",iCase);
            continue;
        }
        b /= k;
        d /= k;
        if(b>d)swap(b,d);
        long long ans1=0;
        for(int i=1;i<=b;i++)
            ans1+=(long long)mu[i]*(b/i)*(d/i);
        long long ans2=0;
        for(int i=1;i<=b;i++)
            ans2+=(long long)mu[i]*(b/i)*(b/i);
        ans1-=ans2/2;
        printf("Case %d: %I64d\n",iCase,ans1);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cacyth/article/details/51182568
今日推荐