分解因式

分解因式 jdoj1370-vijos1229

    题目大意:一个自然数n,求出1~20000中第一个约数个数等于n的数,如果大于20000,则输出No Solution。

    注释:n<=80.在此,我们令N=20000

      想法:开始想暴力,一寻思好像没戏。因为如果是极限数据的话,我们首先枚举到20000就是O(N),然后对于每一个数将它质因数分解,时间复杂度就算用pollard_rho也是$O(N^{frac{1}{4}})$,所以总时间复杂度是$O(N^{frac{5}{4}})$,发现... ...哈哈能过啊,哈哈。咳咳,在此我们介绍更优秀的算法。

      我们用快筛欧拉的思想,外层循环枚举2-N,然后对于当前最大的质因数prime[j],我们用epsilon[i]表示i的约数个数。那么epsilon[i*prime[j]]等于什么呢?很容易想到,因为prime[j]是素数,所以,当i%prime[j]不是0是,即gcd(i,prime[j])=1,所以,对于i的任意一个约数k来讲,k*prime[j]都是i*prime[j]的约数,而且,i*prime[j]的每一个约数,都可以分为i的约数或者i的约数乘以prime[j],这种情况我们就讨论完了。

      那如果是prime[j]|i呢?我们考虑,在i*prime[j]中的什么样的约数是i中没有的,我们设$prime[j]^k||i$,那么,如果有一个数是$prime[j]^{k+1}$的倍数而且是i*prime[j]的约数,那么这个数就是i里不存在的。我们期望统计这样的数有多少个(||的意思是恰整除,$j^k|i$中k的最大值)。显然,如果一个数$m*prime[j]^{k+1}|i*prime[j]$,那么$m|(i/prime[j]^k)$。我们设now=$i/prime[j]^k$。那么,显然,epsilon[now]中的任意一个数乘以$prime[j]^{k+1}$都满足题意,我们只需要快筛的时候把i%prime[j]mod到底即可。

    最后,附上丑陋的代码... ...

 1 #include <iostream>
 2 #include <cstdio>
 3 #define N 20000
 4 using namespace std;
 5 int epsilon[N];
 6 int prime[N];
 7 int cnt;
 8 bool v[N];
 9 int main()
10 {
11     epsilon[1]=1;
12     for(int i=2;i<=N;i++)
13     {
14         if(!v[i]) prime[++cnt]=i,epsilon[i]=2;
15         for(int j=1;j<=cnt&&i*prime[j]<=N;j++)
16         {
17             v[i*prime[j]]=1;
18             if(i%prime[j]==0)//这里就用到了上面所叙述的
19             {
20                 int now=i;
21                 while(now%prime[j]==0) now/=prime[j];
22                 epsilon[i*prime[j]]=epsilon[i]+epsilon[now];//这道水题的精华
23             }
24             else
25                 epsilon[i*prime[j]]=epsilon[i]*2;
26         }
27     }
28     int n;
29     scanf("%d",&n);
30     bool flag=false;
31     for(int i=1;i<=N-10;i++)
32     {
33         if(epsilon[i]==n)
34         {
35             printf("%d
",i);
36             flag=true;
37             break;
38         }
39     }
40     if(!flag) printf("NO SOLUTION
");
41     return 0;
42 }

    小结:我们的想法的切入比较简单,论证上有一些小小的思考而已。

原文地址:https://www.cnblogs.com/ShuraK/p/8428488.html