POJ 2773 Happy 2006 题解与分析

该博客介绍了POJ 2773题目,讨论如何找到第k个与2006互质的正整数。内容涉及最大公约数(GCD)的概念,并要求按升序输出结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Happy 2006
Time Limit: 3000MSMemory Limit: 65536K
Total Submissions: 8447Accepted: 2777

Description

两个正整数如果称为互质,那么应满足这两数的最大公约数(GCD)为1。例如,1,3,5,7,9……都与2006互质。你现在的工作很容易:对于给定的整数m,找到第k个与M互质的元素,这些元素是以升序排序。

Input

输入包含多个测试案例。对于每个测试案例,它包含两个整数m(1 <= m <= 1000000), K (1 <= K <= 100000000).

Output

对于每个案例,输出第k大的与M互质的数,每个数占一行

Sample Input

2006 1
2006 2
2006 3

 

Sample Output

1
3
5

 

Source

 
Translation
 
【分析】:
        这道题目首先想到二分一个数x,表示所求答案在区间[1,x]内,现在需要验证是否在区间[1,x]内有且仅有k个与M互质的数,即求[1,x]中与M互质的数的个数z。这里求z值需转换思想,因为求M的约数比求与M互质的数更快,而求约数可以用M分解因数后的值配上容斥原理解决。那么首先将M分解因数p1-pn,存在数组mult中。
        因为x在区间[1,y]中的倍数有y/x<向下取整>个,那么根据容斥原理,在区间[1,x]内是M的倍数的数为:
                  
        即所有数集合-M以内所有一个素因子构成的因子的个数+M以内所有两个素因子构成的因子的个数-M以内所有三个素因子构成的因子的个数...,那么与M互质的个数就为X-区间[1,x]内是M的倍数的数。
        注意:二分验证完后,不应急于结束二分,因为这里是要求一个下限值x,即在区间[1-x)中与M互质的数的数量刚好小于K,因此应继续让他二分下去
 
【代码】:
/*
     Memory: 8000K  Time: 63MS 
     Language: C++  Result: Accepted 
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAX 1000001
#define IMAX 2147483647
long long M,K,ans,tot=0,change=1;
long long mult[MAX],use[MAX];
void divide1(long long x)
{
      memset(mult,0,sizeof(mult));
      for(long long i=2;i*i<=x;i++)
            if(x%i==0)
            {
                  mult[++tot]=i;
                  while(x%i==0)   x/=i;
            }
      if(x>1)   mult[++tot]=x;     
}
long long check(long long x)
{
      long long sum=0;
      for(long long num=1;num<(1<<tot);num++)//二进制枚举的容斥 
      {
             long long nowsum=1,cnt=0;
             for(int i=1;i<=tot;i++)
             {
                      if(num&(1<<(i-1)))
                      {
                           cnt++;
                           nowsum*=mult[i];
                      }
             }
             if(cnt%2) sum+=x/nowsum;
             else sum-=x/nowsum;
      }
      return (x-sum);      
}
int main()
{
      //freopen("input.in","r",stdin);
	  //freopen("output.out","w",stdout);
      while(scanf("%lld%lld",&M,&K)!=EOF)
      {
            tot=0;
            divide1(M);
            long long left=1,right=IMAX;
            while(left<=right)
            {
                   long long middle=(left+right)/2;
                   long long now=check(middle);
                   if(now>=K)  
                   { 
                         right=middle-1;
                         if(now==K)   ans=middle;
                   }
                   else left=middle+1;
            }
            printf("%lld\n",ans);
      } 
	  //system("pause");
      return 0;
}

转载注明出处:http://blog.youkuaiyun.com/u011400953

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值