您的位置:首页 > 移动开发

POJ 2773 Happy 2006 题解与分析

2013-08-17 19:58 495 查看
[align=center]Happy 2006[/align]

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
POJ Monthly--2006.03.26
 
Translation
初学者 http://blog.csdn.net/csyzcyj
 
【分析】:
        这道题目首先想到二分一个数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.csdn.net/u011400953

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: