pku 3421

pku 3421

这道题从Ac人数以及题目大意上看应属于简单题,但是我却做了好多天 ToT。

刚刚才看了一篇解题报告得到启发过的。题目有点tricky,给一个小于等于2^20的数,本质上要求质因子分解。

题目有接近1/3的提交是超时,其实分解质因子以及后面的计算没什么可说的,主要是求素数表这里会超时。

如果将2到2^20的所有素数打出来,程序长度超过可以提交的限制。如果打一部分,接着在程序里接着算也可以,不过
如果对质因子的上界估计不好的话,也要超时或导致效率低。

最小上界(上确界)是2^10,因为对于a<=2^20最多只有1个质因子会超过2^10,这用反证法很容易得到。因此我们只要算出1024以内
的172个素数即可,程序很快就跑完了。

另外打素数表的时候有一种比较快的算法,虽然只是在朴素算法基础上做了一些小的优化,不过即使在打1024以内素数表就可以体现出
优越性了(69ms VS 79ms),对于更大的素数表,优越性会更明显。

 1  //  pku 3421 给一个整数X,求X的分解。1=X0,X1,X2,,Xm=X,其中Xi整除X(i+1)且Xi<X(i+1),要求最大的m跟有多少种这样长度的链。
 2  //  算法:因为m要最大,所以每次Xi只能乘以一个质因子。若不然可以得到一个更短的链。
 3  //  先求出所有的质因子,所有质因子的排列除以重复的次数就是这种链的个数. 
 4 
 5  #include  < iostream >
 6  #include  < math.h >
 7 
 8  using   namespace  std;
 9 
10  __int64 p[ 172 ];
11  //  因子数目最多是20个
12  int  e[ 21 ];
13  int  cnt;
14  __int64 factor[ 21 ];
15 
16  //  naive method
17  void  prime2()
18  {
19       int  i,j,k,flag;
20      p[ 0 ] = 2 ;
21      cnt = 1 ;
22       for (i = 3 ;i < 1024 ;i ++ ){
23          flag = 0 ;
24          j = sqrt( 1.0 * i);
25 
26           for (k = 2 ;k <= j;k ++ ){
27               if (i % k == 0 ) {flag = 1 ; break ;}
28          }
29           if ( ! flag) p[cnt ++ ] = i;
30      }
31  }
32 
33  void  prime()
34  {
35       int  i,j,flag;
36      p[ 0 ] = 2 ;
37      p[ 1 ] = 3 ;
38      cnt = 2 ;
39       for (i = 5 ;i <= 1024 ;i += 2 ){
40          flag = 0 ;
41           for (j = 1 ;p[j] * p[j] <= i;j ++ ){
42               if (i % p[j] == 0 ) {flag = 1 ; break ;}
43          }
44           if ( ! flag) p[cnt ++ ] = i;
45      }
46  }
47 
48  //  先质因子分解,再求组合的个数
49  void  solve(__int64 a)
50  {
51       //  j统计所有质因子的个数,k统计不同质因子个数
52       int  i,j = 0 ,flag,l = 0 ;
53      memset(e, 0 , sizeof (e));
54       //  用1024以内的素数分解a,注意到a<=2^20,a最多含有一个超过1024的质因子 
55       //  a=p1^e1*p2^e2**pk^ek*ps^es,其中只有ps是大于1024的素数,且es只能为0或1
56       for (i = 0 ;i < cnt  &&  a > 1 ;i ++ ){
57          flag = 0 ;
58           while (a % p[i] == 0 ){
59              flag = 1 ;
60              e[l] ++ ;
61              a /= p[i];
62              j ++ ;
63          }
64           if (flag == 1 ) l ++ ;
65      }
66       //  若此时a!=1则a一定是素数
67       if (a != 1 ) {j ++ ;e[l ++ ] = 1 ;}
68      __int64 res  =  factor[j];
69       for (i = 0 ;i < l;i ++ ){
70           if (e[i] != 0 ) res /= factor[e[i]];
71      }
72      printf( " %d %I64d\n " ,j,res);
73  }
74 
75  int  main()
76  {
77      prime1();
78       // cnt=172;
79       //  阶乘
80      factor[ 0 ] = 1 ;
81       for (__int64 i = 1 ;i < 21 ;i ++ ) factor[i] = factor[i - 1 ] * i;
82      __int64 a;
83       while (scanf( " %I64d " , & a) != EOF){
84          solve(a);
85      }
86      
87       return   1 ;
88  }
89 

你可能感兴趣的:(pku 3421)