【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;
}

浙公网安备 33010602011771号