Phi(m)为与乘法群模m的规模,将区间分段,每段长度m,每个区间内有phi(m)个与m互素的数,枚举第一段的所有互素数coprime[i],结果为m*(k/phi[m])+coprime(k%phi[m]),注意特殊处理phi[m]整数倍数的数。参考网上的一些代码,学会了快速求互素数的方法。时间:47ms。上代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MAX=1000000;
bool isprime[MAX+10],isfactor[MAX+10];//是否是素数
int coprime[MAX+10],prime[MAX+10],primefactor[MAX+10];//互素数,素数,素数因子
void getprime()//筛素数
{
long long i,j;
int cnt=0;
memset(isprime,1,sizeof(isprime));
isprime[0]=isprime[1]=0;
for(i=2;i*i<=MAX;i++)
{
if(isprime[i])
{
prime[++cnt]=i;
for(j=i*i;j<=MAX;j+=i)
isprime[j]=0;
}
}
prime[0]=cnt;
}
void getprimefactor(int n)//求素数因子,primefactor[0]即为素数因子的个数
{
int cnt=0;
for(int i=1;prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
primefactor[++cnt]=prime[i];
while(n%prime[i]==0)
n/=prime[i];
}
}
if(n>1)
primefactor[++cnt]=n;
primefactor[0]=cnt;
}
void getcoprime(int n)//筛出互素数,coprime[0]即为欧拉函数
{
int cnt=0;
memset(isfactor,0,sizeof(isfactor));
for(int i=1;i<=primefactor[0];i++)
{
for(int j=primefactor[i];j<=n;j+=primefactor[i])
isfactor[j]=1;
}
for(int i=1;i<=n;i++)
{
if(!isfactor[i])
coprime[++cnt]=i;
}
coprime[0]=cnt;
}
int main()
{
long long n,ind,i;
getprime();
freopen("in.txt","r",stdin);
while(scanf("%lld%lld",&n,&ind)!=EOF)
{
getprimefactor(n);
getcoprime(n);
long long a,b,ret,rr;
a=ind/coprime[0];
b=ind-a*coprime[0];
if(b==0)
printf("%lld\n",n*(a-1)+coprime[coprime[0]]);
else
printf("%lld\n",a*n+coprime[b]);
}
return 0;
}