poj2773(欧拉函数的应用 或者 用容斥原理+dfs+二分)

题意:给出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;     
}



 




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值