【HDOJ 2588】GCD 欧拉函数

https://acm.hdu.edu.cn/showproblem.php?pid=2588

思路

如果直接枚举n,肯定会超时,考虑其他做法

设 N = M * b, x = M * d. 因为(N,x)=M , 所以 (b,d)=1
由上面可以推出 (N/M,x/M)=1
所以x的个数即为枚举M时,φ(N/M)的累加

关于为什么不会有重复的,简易证明如下:

只有存在 (ka,kb)=1 , (a,b)=1时,才有x=bN/a存在。 这与第一个条件矛盾,因为(ka,k*b)=k 默认k>1

code

此外还需要注意单纯枚举所有m会超时,需要加以优化:

1.枚举sqrt(n)个m

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200005;
int t,n,m;

int Euler(int n){   
    int nn=n;
    int ans=n;
    for(int i=2;i*i<=nn;i++){
        if(n%i==0){
            ans=ans-ans/i;
            while(n%i==0){
                n/=i;
            }
        }
    }
    if(n>1){
        ans=ans-ans/n;
    }
    return ans;
} 

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        if(m==1){
            printf("%d\n",n);
            continue;
        }
        ll ans=0;
        for(int i=1;i*i<=n;i++){
            if(n%i!=0) continue;
            if(i>=m) ans+=Euler(n/i);
            if(n/i>=m && i*i!=n) ans+=Euler(i);
        }
        printf("%lld\n",ans);
    }
    system("pause");
    return 0;
}

用队列表示出所有可能的m

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200005;
int t,n,m,nn;
queue<int>q,tem;

void init(){
    q.push(1);
    for(int i=2;i*i<=nn;i++){
        if(i>n) break;
        if(n%i==0){
            int cnt=0;
            while(n%i==0){
                n/=i;
                cnt++;
            }
            while(!q.empty()){
                int now=q.front();
                q.pop();
                int ttem=1;  tem.push(now);
                for(int j=1;j<=cnt;j++){
                    ttem=ttem*i;
                    tem.push(now*ttem);
                }
            }
            while(!tem.empty()){
                int now=tem.front();
                tem.pop();
                q.push(now);
            }
        }
    }
    if(n>1){
        while(1){
            int now=q.front();
            if(now%n==0) break;
            q.pop();
            q.push(now*n);
            q.push(now);
        }
    }
}

int Euler(int n){   
	int nn=n;
	int ans=n;
	for(int i=2;i*i<=nn;i++){
		if(n%i==0){
			ans=ans-ans/i;
			while(n%i==0){
				n/=i;
			}
		}
	}
	if(n>1){
		ans=ans-ans/n;
	}
	return ans;
} 

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        nn=n;
        if(m==1){
            printf("%d\n",n);
            continue;
        }
        init();
        ll ans=0;
        while(!q.empty()){
            int now=q.front();
            q.pop();
            if(now<m) continue;
            // cout<<now<<endl;
            ans+=Euler(nn/now);
        }
        printf("%lld\n",ans);
    }
    system("pause");
    return 0;
}
posted @ 2022-07-22 15:14  starlightlmy  阅读(42)  评论(0)    收藏  举报