POJ 2773 Happy 2006(求第k个与m互素的数)

来源:互联网 发布:淘宝药店旗舰店靠谱吗 编辑:程序博客网 时间:2024/05/29 04:54
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


原理是欧几里得算法的变形:gcd(b×t+a,b)=gcd(a,b)(t为任意整数),

则如果a与b互素,则b×t+a与b也一定互素,如果a与b不互素,则b×t+a与b也一定不互素

故与m互素的数对m取模具有周期性。

例如m=9,小于m且和m互素的数有6个:1、2、4、5、7、8.

大于m且和m互素的数具有周期性:10(=9*1+1)、11(=9*1+2)、13(=9*1+4)...17(=9*1+8)、19(=9*2+1)...

还有值得注意的是:在计算小于m且和m互素的数时,如果用gcd(m,i)==1依次判断时间会比较长(2000+ms),如下:

#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cctype>#include<cmath>#include<algorithm>#include<string>#include<stack>#include<ctime>#include<vector>#include<map>#include<climits>using namespace std;const int M = 1000005;typedef long long LL;int p[M];int gcd(int a,int b){    int t;    while(b!=0)    {        t=a%b;        a=b;        b=t;    }    return a;}int main(){    //freopen("in.txt","r",stdin);    int m,k;    while(~scanf("%d%d",&m,&k)){        int j=1;        for(int i=1;i<=m;i++)            if(gcd(m,i)==1)                p[j++]=i;        j--;        if(k%j) printf("%d\n",p[k%j]+k/j*m);        else printf("%d\n",p[j]+(k/j-1)*m);    }    return 0;}

用以下这种筛法会省时得多(100+ms)

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#define LL long long#define mset(x,y) memset(x,y,sizeof(x))using namespace std;bool F[1100000];//F[i]=1表示i与m有公约数,F[i]=0表示i与m互素int p[1100000];//p[i]表示第i个与m互素的数int main(){    int m,k;    //while (scanf("%d%d",&m,&k)!=EOF)    while (cin>>m>>k)    {        mset(F,0);        for (int i=2;i<=m;i++)        {            if (!F[i] && m%i==0)            {                int j=i*2;                F[i]=1;                while (j<m)                {                    F[j]=1;                    j+=i;                }            }        }        p[0]=0;        F[1]=0;        for (int i=1;i<=m;i++)        {            if (!F[i])            {                p[0]++;                p[p[0]]=i;            }        }/*后面都一样*/        int o=p[0];        int x,y;        x=k/o;        y=k%o;        LL ans;        if (y==0) {y=p[0];x--;}        ans=x*m+p[y];        cout<<ans<<endl;    }    return 0;}






0 0
原创粉丝点击