poj2773如何运用二分和容斥原理求解欧拉函数?

2026-05-29 14:503阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1297个文字,预计阅读时间需要6分钟。

poj2773如何运用二分和容斥原理求解欧拉函数?

欧几里得定理告诉我们gcd(n, m)=gcd(n, n-m),那么就有gcd(n, m)=gcd(n, n+m)。因此,对于n个数的gcd取值情况,实际上与n个数的gcd取值情况是相同的。

然后,可以利用欧拉函数的性质将问题转化为在n内的某个问题。之后,可以进一步利用欧拉函数的性质将问题转化为在n内的某个问题。

最后,可以得出结论:gcd(n, m)=gcd(n, n+m)=gcd(n, n-m)。


欧几里得定理告诉我们gcd(n,m)==gcd(n,n-m),那么就有gcd(n,m)==gcd(n,n+m)

因此,对每n个数,与n取gcd的情况其实是相同的。。

然后可以利用欧拉函数把m的问题转化为在n内的问题。。

然后剩下的就是如何在1..n找第m个和n互斥的数了。。

直接枚举貌似可以过。。然而这样还要预处理欧拉函数干嘛。。所以肯定有更快的做法。。

找数肯定用二分查找比较优秀,关键是如何check。。

最主要还是找出1..t内有多少数和n互斥,其实对n分解质因数后就可以用容斥做了。。

考虑到质因子的平均个数为loglogn,所以复杂度为O(Tlog^2n+n)

/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 1000005
#define nm 200005
#define N 40005
#define M(x,y) x=max(x,y)
const double pi=acos(-1);
const int inf=1e9;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}


int n,m,c[NM],tot,phi[NM],prime[NM],_x,cnt,s;
bool v[NM];
ll ans;

void Euler(){
n=1e6;phi[1]=1;
inc(i,2,n){
if(!v[i])prime[++tot]=i,phi[i]=i-1;
inc(j,1,tot){
if(i*prime[j]>n)break;
v[i*prime[j]]++;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}


void dfs(int i,int s,int t){
if(s>_x)return;
if(i==tot+1){if(s>1)cnt+=_x/s*(t&1?1:-1);return;}
dfs(i+1,s,t);dfs(i+1,s*c[i],t+1);
}

bool check(int x){
cnt=_x=x;dfs(1,1,1);
return cnt<=m;
}

int main(){
Euler();
while(~scanf("%d%d",&n,&m)){
ans=(ll)m/phi[n]*n;m%=phi[n];
if(m==0)ans-=n,m=phi[n];
int t=n;tot=0;
inc(i,2,sqrt(t))if(t%i==0){
c[++tot]=i;
while(t%i==0)t/=i;
}
if(t>1)c[++tot]=t;
for(int x=1,y=n;x<=y;)
if(check(mid))s=mid,x=mid+1;else y=mid-1;
while(__gcd(s,n)>1)s--;
ans+=s;
printf("%lld\n",ans);
}
return 0;
}

Happy 2006

Description

Two positive integers are said to be relatively prime to each other if the Great Common Divisor (GCD) is 1. For instance, 1, 3, 5, 7, 9...are all relatively prime to 2006.

Now your job is easy: for the given integer m, find the K-th element which is relatively prime to m when these elements are sorted in ascending order.

Input

The input contains multiple test cases. For each test case, it contains two integers m (1 <= m <= 1000000), K (1 <= K <= 100000000).

Output

Output the K-th element in a single line.

Sample Input

2006 1
2006 2
2006 3

Sample Output

1
3
5

Source

​​POJ Monthly--2006.03.26​​,static

Time Limit: 3000MS


Memory Limit: 65536K

Total Submissions: 14121


Accepted: 4995

[​​Submit​​​] [Go Back] [​​Status​​​] [​​Discuss​​]

poj2773如何运用二分和容斥原理求解欧拉函数?

本文共计1297个文字,预计阅读时间需要6分钟。

poj2773如何运用二分和容斥原理求解欧拉函数?

欧几里得定理告诉我们gcd(n, m)=gcd(n, n-m),那么就有gcd(n, m)=gcd(n, n+m)。因此,对于n个数的gcd取值情况,实际上与n个数的gcd取值情况是相同的。

然后,可以利用欧拉函数的性质将问题转化为在n内的某个问题。之后,可以进一步利用欧拉函数的性质将问题转化为在n内的某个问题。

最后,可以得出结论:gcd(n, m)=gcd(n, n+m)=gcd(n, n-m)。


欧几里得定理告诉我们gcd(n,m)==gcd(n,n-m),那么就有gcd(n,m)==gcd(n,n+m)

因此,对每n个数,与n取gcd的情况其实是相同的。。

然后可以利用欧拉函数把m的问题转化为在n内的问题。。

然后剩下的就是如何在1..n找第m个和n互斥的数了。。

直接枚举貌似可以过。。然而这样还要预处理欧拉函数干嘛。。所以肯定有更快的做法。。

找数肯定用二分查找比较优秀,关键是如何check。。

最主要还是找出1..t内有多少数和n互斥,其实对n分解质因数后就可以用容斥做了。。

考虑到质因子的平均个数为loglogn,所以复杂度为O(Tlog^2n+n)

/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 1000005
#define nm 200005
#define N 40005
#define M(x,y) x=max(x,y)
const double pi=acos(-1);
const int inf=1e9;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}


int n,m,c[NM],tot,phi[NM],prime[NM],_x,cnt,s;
bool v[NM];
ll ans;

void Euler(){
n=1e6;phi[1]=1;
inc(i,2,n){
if(!v[i])prime[++tot]=i,phi[i]=i-1;
inc(j,1,tot){
if(i*prime[j]>n)break;
v[i*prime[j]]++;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}


void dfs(int i,int s,int t){
if(s>_x)return;
if(i==tot+1){if(s>1)cnt+=_x/s*(t&1?1:-1);return;}
dfs(i+1,s,t);dfs(i+1,s*c[i],t+1);
}

bool check(int x){
cnt=_x=x;dfs(1,1,1);
return cnt<=m;
}

int main(){
Euler();
while(~scanf("%d%d",&n,&m)){
ans=(ll)m/phi[n]*n;m%=phi[n];
if(m==0)ans-=n,m=phi[n];
int t=n;tot=0;
inc(i,2,sqrt(t))if(t%i==0){
c[++tot]=i;
while(t%i==0)t/=i;
}
if(t>1)c[++tot]=t;
for(int x=1,y=n;x<=y;)
if(check(mid))s=mid,x=mid+1;else y=mid-1;
while(__gcd(s,n)>1)s--;
ans+=s;
printf("%lld\n",ans);
}
return 0;
}

Happy 2006

Description

Two positive integers are said to be relatively prime to each other if the Great Common Divisor (GCD) is 1. For instance, 1, 3, 5, 7, 9...are all relatively prime to 2006.

Now your job is easy: for the given integer m, find the K-th element which is relatively prime to m when these elements are sorted in ascending order.

Input

The input contains multiple test cases. For each test case, it contains two integers m (1 <= m <= 1000000), K (1 <= K <= 100000000).

Output

Output the K-th element in a single line.

Sample Input

2006 1
2006 2
2006 3

Sample Output

1
3
5

Source

​​POJ Monthly--2006.03.26​​,static

Time Limit: 3000MS


Memory Limit: 65536K

Total Submissions: 14121


Accepted: 4995

[​​Submit​​​] [Go Back] [​​Status​​​] [​​Discuss​​]

poj2773如何运用二分和容斥原理求解欧拉函数?