poj2773如何运用二分和容斥原理求解欧拉函数?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1297个文字,预计阅读时间需要6分钟。
欧几里得定理告诉我们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 12006 2
2006 3
Sample Output
13
5
Source
POJ Monthly--2006.03.26,static
Time Limit: 3000MS
Memory Limit: 65536K
Total Submissions: 14121
Accepted: 4995
[Submit] [Go Back] [Status] [Discuss]
本文共计1297个文字,预计阅读时间需要6分钟。
欧几里得定理告诉我们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 12006 2
2006 3
Sample Output
13
5
Source
POJ Monthly--2006.03.26,static
Time Limit: 3000MS
Memory Limit: 65536K
Total Submissions: 14121
Accepted: 4995
[Submit] [Go Back] [Status] [Discuss]

