poj2773(欧拉函数+二分+容斥)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qkoqhh/article/details/81953083

欧几里得定理告诉我们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

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 14121   Accepted: 4995

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

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

猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/81953083