题意 : 求与n互质的第k大的数
容斥原理:
1到m中与n互质的个数为 m - (与n不互质的数的个数) 于是根据容斥原理,首先求出n的所有的素因子,对于1到m,
与n不互质的数为 m - (m以内所有一个素因子构成的因子的个数) + (m以内所有两个素因子构成的因子的个数) - (m以内所有三个素因子构成的因子的个数)。。。
刚开始wrong answer了两次,原来居然把二分的范围限制在了1到n,后来改成10^9就AC了
欧拉函数:
phi(n)表示1到n中与n互质的数的个数 , 区间(1 , n)与 区间(n+1 , 2n)中与n互质的数都是一一对应的,这个很容易得到,有了这个循环节,我们就可以枚举1到n求出第k%phi(n)个互质数就行了
容斥原理
#include <stdio.h>
int f[222];
int change , top , k , d[222] ;
const int maxn = 1000000000;
int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;
}
void rongchi(int now,int num,int tot,int x) // now当前处理到的素因子,num当前有的素因子个数,总的素因子个数
{
// 以前写搓了,直接就用二进制压缩位来求多简单。。。现在就不改了
int i;
if(num==tot)
{
int sum = 1;
for(i = 0;i < num ;i++)
sum *= d[i];
change += x/sum;
}
else
for(i = now;i < top; i++)
{
d[num] = f[i];
rongchi(i+1,num+1,tot,x);
}
}
int bin(int n,int tot,int l,int r)
{
int i,j;
while(l<=r)
{
int mid = (l+r)>>1;
for(i = 0;i < tot; i++)
if(f[i]>mid)
break;
int sum = mid;
top = i;
for(j = 0;j < i ;j++) // 求出mid以内与m互质的个数
{
change = 0;
rongchi(0,0,j+1,mid);
if(j&1)
sum += change;
else
sum -= change;
}
// printf("%d %d %d %d\n",l,mid,r,sum);
if(sum == k)
{
for(i = mid;i >= 1; i--)
if(gcd(n,i)==1) // 找到mid以内第k个与m互质的数
return i;
}
if(sum > k)
r = mid-1;
else
l = mid+1;
}
}
int main()
{
int n, i;
while(scanf("%d%d", &n, &k)!=-1)
{
int m = n;
int tot = 0;
for(i = 2;i*i <= n ;i++)
{
if(n%i==0)
{
while(n%i==0)
n /= i;
f[tot++] = i; // 预处理出素因子
}
}
if(n!=1)
f[tot++] = n;
printf("%d\n",bin(m,tot,1,maxn));
}
return 0;
}
欧拉函数
#include <stdio.h>
int f[111];
int gcd(int a,int b){
return b ? gcd(b , a%b) : a;
}
int main()
{
int n,k,i;
while(scanf("%d%d", &n ,&k)!=-1)
{
if(n == 1)
{
printf("%d\n", k);
continue;
}
int m = n;
int tot = 0;
for(i = 2;i*i <= m ;i ++)
if(m%i == 0)
{
while(m%i==0) // 筛选素因子
m /= i;
f[tot++] = i;
}
if(m != 1)
f[tot++] = m;
int sum = n;
for(i = 0;i < tot; i++)
sum = sum - sum/f[i];
if(k%sum == 0) // 如果k刚好是phi(n)的倍数,就只需要找出第phi(n)个互质数
{
for(i = n-1;i >= 1; i--)
if(gcd(i , n)==1)
break;
printf("%d\n", (k/sum-1)*n+i);
}
else
{
int ans = k/sum*n;
k = k%sum;
for(i = 1;i < n && k>0; i++) // 枚举找到第k%phi(n)个数
if(gcd(i , n) == 1)
k--;
printf("%d\n" , ans + i-1);
}
}
return 0;
}