hdu2447 K-dimension number

这是一个有亮点的题目~~

题目告诉K的因子个数d<=3
分析可知:(有唯一分解定理容易推出)
d=1时  K=1 ans=1
d=2时  K为质数 ans=pn^K-1
d=3时  K为质数p的平方 ans=pi^(p^2-1),或 ans=(pi*pj)^(p-1) , i不等于j  (两个pi没啥关系)

前两种情况好处理。

第三种情况需要在形如pi^(p^2-1)和(pi*pj)^(p-1)这样的数中寻找第n小的数。

可以分别找出两者前n小的2n个数,再利用归并排序的思想找到两者中第n小的数。

对于pi^(p^2-1)这样的数,直接枚举质数就好。

然后,亮点来了~~

对于(pi*pj)^(p-1)这样的数

如果两重循环直接枚举pi和pj,为了确保可以得到前n个最小的乘积,需要先n*(n-1)/2的枚举,再排序,复杂度O(n^2+n^2log(n^2))。

n<10000,复杂度太高。

可以利用bfs+优先队列+set判重来枚举,效率还是挺高的,但是这题涉及大数,如果用JAVA来实现那些容器,不太好写。。。

可以换个思路,枚举乘积的结果,再判断这个结果可不可以分解成两个不同的质数。

在这里要介绍这个线性筛素数的代码,不仅可以O(n)得到1……n的素数表,还可以得到1……n中每个数的最小质因子,很强大的。

可以多读几遍,我的理解是每个合数X只唯一地被数X/p1筛掉,p1是X的最小素因子。

 1 const int N = 105000;
 2 
 3 int prime[N/10],pd[N+5],pnum;
 4 
 5 void gp()
 6 {
 7     for(int i=2;i<=N;i++)
 8     {
 9         if( 0==pd[i] )  prime[++pnum]=pd[i]=i;
10         for(int j=1;j<=pnum && i<=N/prime[j];j++)
11         {
12             pd[i*prime[j]]=prime[j];
13             if( i%prime[j]==0 ) break;
14         }
15     }
16 }

利用上面这段代码,可以很高效的实现刚才的思路。

对于枚举的乘积结果i,令x=i/pd[i], 则 若( pd[x]==x && x!=pd[i] )那么i就是合法的一个乘积结果啦。

枚举的界限可以定在prime[1]*prime[10001]=209486 。

问题解决啦~~

 1 import java.util.*;
 2 import java.math.*;
 3 
 4 public class Main 
 5 {
 6     public static void main(String[] args)
 7     {
 8         final int N = 105000;
 9         int pnum=0;
10         int[] prime = new int[10050];
11         int[] pd = new int[N+5];
12         int cnt=0;
13         int[] p1 = new int[10005];
14         
15         for(int i=1;i<=N;i++)    pd[i]=0;
16         for(int i=2;i<=N;i++)
17         {
18             if( 0==pd[i] )    prime[++pnum]=pd[i]=i;
19             for(int j=1;j<=pnum && prime[j]<=N/i;j++)
20             {
21                 pd[i*prime[j]]=prime[j];
22                 if( i%prime[j]==0 )    break;
23             }
24         }
25         for(int i=6;i<=209486;i++)
26         {
27             int x=i/pd[i];
28             if( pd[x]==x && x!=pd[i] )
29             {
30                 p1[++cnt]=i;
31                 if( cnt>=10000 )    break;
32             }
33         }
34         
35         Scanner scan = new Scanner(System.in);
36         int n,k;
37         while( scan.hasNextInt() )
38         {
39             n=scan.nextInt();
40             k=scan.nextInt();
41             if( 1==k )    System.out.println("1");
42             else if( pd[k]==k )
43             {
44                 BigInteger ret=BigInteger.valueOf(prime[n]);
45                 ret=ret.pow(k-1);
46                 System.out.println(ret);
47             }
48             else
49             {
50                 int i=1,j=1,p=(int)Math.sqrt((double)k);
51                 BigInteger ret;
52                 while( true )
53                 {
54                     double x=(double)(p-1)*Math.log10(p1[i]),y=(double)(k-1)*Math.log10(prime[j]);
55                     if( x<y )    
56                     {
57                         i++;
58                         if( i+j-2==n )    {ret=BigInteger.valueOf(p1[i-1]).pow(p-1);break;}
59                     }
60                     else if( x>y )    
61                     {
62                         j++;
63                         if( i+j-2==n )    {ret=BigInteger.valueOf(prime[j-1]).pow(k-1);break;}
64                     }
65                     else 
66                     {
67                         i++;
68                         j++;
69                         if( i+j-2>=n )    {ret=BigInteger.valueOf(p1[i-1]).pow(p-1);break;}
70                     }
71                 }
72                 System.out.println(ret);
73             }
74         }
75     }
76 }
View Code

 

posted @ 2013-06-05 21:23  kiwi_bird  阅读(393)  评论(0编辑  收藏  举报