反素数就是区间内约数个数最多的那个数。

在ACM题目里,

一般是求约数最多而且数字最小的那个数,【1--n】

二是求约数刚好等于n的最小的那个数

三是求区间里的最小反素数【beign,end】

1和3有区别吗?有,1可以加速,3只能暴力

先说下思路

思路 : 官方题解 : 

(1)此题最容易想到的是穷举,但是肯定超时。

(2)我们可以知道,计算约数的个数和质因数分解有着很大的联系: 若Q的质因数分解为:Q=p1^k1*p2^k2*…*pm^km(p1…pm为素数,k1…km≥1),则Q有(k1+1)(k2+1)…(km+1)个约数。但是质因数分解的时间复杂度很高,所以也会超时。

(3)通过以上的公式,我们可以“突发奇想”:为何不能把质因数分解的过程反过来呢? 这个算法就是枚举每一个素数。初始时让m=1,然后从最小的素数2开始枚举,枚举因子中包含0个2、1个2、2个2…k个2,直至m*2^k大于区间的上限N。在这个基础上枚举3、5、7……的情况,算出现在已经得到的m的约数个数,同时与原有的记录进行比较和替换。直至所有的情况都被判定过了。 这个算法的优化:如果p1*p2*p3*……*pk>N(pi表示第i个素数),那么只要枚举到p k-1,既不浪费时间,也不会遗漏。

(4)以上的算法还不是最好的,还可以继续优化。 我们看以下的例子: 6=2*3 10=2*5 6和10的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于3<5,所以6<10。 12=2^2*3 18=3^2*2 12和18的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于12的质因数分解中2的指数大于3的指数,18的质因数分解中3的指数大于2的指数,所以12<18。 根据以上的举例,我们也可以对(3)中的算法进行一个改进:可以在枚举时进行一个优化,使得枚举到的数字中2的指数不小于3的指数,3的指数不小于5的指数……这样我们就能够得到质因数分解“模式”相同的最小数(证明略)。再对于每一个得到的数进行比较和记录。这个算法的优化力度极大,效率几乎达到了极限。

 

每个思路都很好理解,所以

http://codeforces.com/problemset/problem/27/E

这是签到题了,约数刚好等于n,那么最需dfs的时候判断即可,用第4这个方法的思路,time 30ms

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
LL pr, mx, BEGIN, END = 1e18;
const int maxn=50+20;
int prime[maxn];//这个记得用int,他保存的是质数,可以不用开maxn那么大
bool check[maxn];
int total;
int n;
void initprime() {
    for (int i=2; i<=maxn-20; i++) {
        if (!check[i]) { //是质数了
            prime[++total]=i;//只能这样记录,因为后面要用
        }
        for (int j=1; j<=total; j++) { //质数或者合数都进行的
            if (i*prime[j]>maxn-20) break;
            check[i*prime[j]]=1;
            if (i%prime[j]==0) break;
            //关键,使得它只被最小的质数筛去。例如i等于6的时候。
            //当时的质数只有2,3,5。6和2结合筛去了12,就break了
            //18留下等9的时候,9*2=18筛去
        }
    }
    return ;
}
void dfs(LL curnum, int cnt, int depth, int up) {
    if (depth > total) return ; // 越界了,用不到那么多素数
    if ((cnt > mx || cnt == mx && pr > curnum) && cnt == n) {
        pr = curnum;
        mx = cnt;
    }
    for (int i = 1; i <= up; ++i) { //枚举有多少个prime[depth]
        if (END / curnum < prime[depth]) return ;
        if ((BEGIN - 1) / curnum == END / curnum) return ; //区间不存在这个数的倍数
        curnum *= prime[depth]; //一路连乘上去
        dfs(curnum, cnt * (i + 1), depth + 1, i); // 2^2 * 3, 3最多2个
    }
}

void work() {
    cin >> n;
    dfs(1, 1, 1, 64);
    cout << pr << endl;
    return ;
}

int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    initprime();
    work();
    return 0;
}
View Code

相关文章:

  • 2021-09-19
  • 2021-08-31
  • 2021-11-11
  • 2021-06-29
  • 2021-11-17
  • 2021-10-28
  • 2022-02-23
猜你喜欢
  • 2021-09-01
  • 2021-06-26
  • 2022-03-06
  • 2021-07-08
相关资源
相似解决方案