POJ 2773
题意 : 求与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; }