2011-12-31 01:58:02
地址:http://acm.hdu.edu.cn/showproblem.php?pid=1239
题意:给m、a、b。求一对素数p,q(p<q)使得p*q<=m且p/q >= a/b。若有多对,输出p*q最大的一对。
mark:刚开题看了半天,才看明白啥意思。
看到m是10w,然后case是2000组,一下懵了,以为不能枚举。后来冷静分析下,其实可以。
以下是几个比较重要的结论&分析。
1)若m' = p*q,则必不存在另外一对素数p',q'使得m' = p' * q'。
2) 若p固定,q要满足:1、p*q<=m;2、p/q>=a/b。则可以推出q是满足小于min(m/p, p*b/a)的素数,而因为要求p*q最大,所以q应该是满足条件的最大素数。
3) 因为p>=q而且要求p*q <=m,所以p <=sqrt(m)。
因此,我们只需要从2到sqrt(m)枚举每个素数p,计算出相应的q。m是10w,开根号只有300多,非常小,素数就更少了。即使是2000*300也是可以接受的。
代码:
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
int IsPrime[50010] = {1, 1} ;
int Primes[10000] ;
int pcnt = 0 ;
void init()
{
int i, j ;
for (i = 2 ; i <= 50003 ; i++)
{
if (!IsPrime[i])
{
Primes[pcnt++] = i ;
for (j = 2*i ; j <= 50003 ; j+=i)
IsPrime[j] = 1 ;
}
}
}
int min(int a, int b){return a<b?a:b;}
int main ()
{
int m, a, b, sqrtm ;
int p, q, ansp, ansq ;
init () ;
while (~scanf ("%d%d%d", &m, &a, &b) && (m||a||b))
{
sqrtm = sqrt(1.0*m) ;
ansp = ansq = 1 ;
for (p = 0 ; Primes[p] <= sqrtm ; p++)
{
q = min(m/Primes[p], Primes[p]*b/a) ;
while (IsPrime[q]) q-- ;
if (Primes[p]*q > ansp * ansq)
ansp = Primes[p], ansq = q ;
}
printf ("%d %d\n", ansp, ansq) ;
}
return 0 ;
}