题意:给出m和k,求与m互质的第k个数
方法一:要用到的知识点:如果a和m互质,那么k*m+a和m也互质
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
int euler_phi(int n)
{
int m = (int)sqrt(n + 0.5);
int ans = n;
for(int i = 2; i <= m; i++)
if(n % i == 0)
{
ans = ans / i * (i-1);
while(n % i == 0) n /= i;
}
if(n > 1) ans = ans / n * (n - 1);
return ans;
}
int gcd(int a,int b)
{
return b % a == 0 ? a : gcd(b%a , a);
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int n,k;
while(scanf("%d%d",&n,&k) != EOF)
{
int ans = euler_phi(n);
int temp = k / ans;
if(k % ans == 0) temp--;
int k1 = k - temp*ans;
int i = 1;
while(k1)
{
if(i > n) swap(i,n);
if(gcd(i,n) == 1)
k1--;
i++;
}
printf("%d\n",temp*n + i - 1);
}
// P;
return 0;
}
接在来在介绍用容斥原理来解这道题,我本来打算用容斥原理来做,可是觉得太难了,后来就借鉴了网上的方法用欧拉函数解,
现在又回过头来用容斥原理+二分+dfs解,对于我这种菜鸟来说太难了,花了一个下午才A的
下面的思路我参考大神的。
问题的关键就是求1到mid之间与n互质的数,但是我们先求不与n互质的数,然后用mid减求出的数就是与n互质的数,
此外,还要求n的质因子p1,p2,...pk
接下来就要用到容斥原理,现假设mid = 13,n是12,ans = mid/2 + mid/3 - mid/(2*3) ,然后所求的值就是mid - ans
用二分是为了不断更新mid的值。
下面附上代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>
#define ll long long
#define inf 0x7fffffff
#define eps 1e-9
#define N 1000000
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
ll prime[N+10],d[N];
bool vis[N+10];
int gen_primes()//求1000000以内的质数
{
ll i,j;
ll m = (int)sqrt(N+0.5);
memset(vis,0,sizeof(vis));
for(i = 2; i <= m; i++)
if(!vis[i])
for(j = i * i; j <= N; j +=i)
vis[j] = 1;
j = 0;
for(i = 2; i <= N; i++)
if(!vis[i])
prime[j++] = i;
return j;
}
void dfs(ll cur,ll now,ll mid,bool flag,ll j,ll &ans) //搜索的形式+容斥原理的思想。cur代表当前质因子的下标,
{//now代表当前质因子的积,flag是为了确定加减法,ans记录不与n互质的数的个数
if(cur >= j) return;
dfs(cur+1,now,mid,flag,j,ans);
ll n = now*d[cur]; //??为什么不是cur+1
if(flag) ans += mid / n;
else ans -= mid / n;
dfs(cur+1,n,mid,!flag,j,ans);
}
ll sum(ll mid,ll j)
{
//memset(vis)
ll ans = 0;
dfs(0,1,mid,1,j,ans);
return mid - ans;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
ll c = gen_primes();
ll n,k;
//cout<<c<<endl;
while(scanf("%lld%lld",&n,&k) != EOF)
{
ll i,j;
j = 0;
for(i = 0; i < c; i++){ //求n的质因子
if(n % prime[i] == 0)
{
d[j++] = prime[i];
while(n % prime[i] == 0) n /= prime[i];
}
if(n == 1) break;
}
ll low = 1, high = inf;
ll ans;
while(low <= high)//二分搜索,不断更新mid的值
{
ll mid = (high + low) / 2;
ll temp = sum(mid, j);
if(temp == k) ans = mid;
if(temp < k) low = mid + 1;
else high = mid - 1;
}
printf("%lld\n",ans);
}
// P;
return 0;
}