zoukankan      html  css  js  c++  java
  • luogu 1463

    题目描述:

    对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。

    如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。例如,整数1,2,4,6等都是反质数。

    现在给定一个数N,你能求出不超过N的最大的反质数么?

    N<=2e9。

    (暴力出奇迹(´థ౪థ)σ)

    不打表的AC做法见洛谷题解区。

    设将X质因数分解后为X=p1^n1 * p2^n2 * ... * pk^nk,那么X的约数个数为(n1 + 1) * (n2 + 1) * ... * (nk + 1)。

    这道题如果要打表的话,最暴力的算法是:枚举for X = 1 to 2e9,将X质因数分解后统计约数个数。但这样做的话5个小时恐怕都打不出表来。

    不妨设X=p^n * ...,其中p是某个质数,省略号部分是其他质因子。不难得出g(X) = (n + 1) * g(X / p^n),利用这个式子可以大幅优化枚举过程。

    考虑到空间有限,我们可以将前N个数的约数个数g(1)~g(N)保存起来(我的代码中取了N=2.4e8)。在质因数分解过程中,如果X / p^n <= N,那么就不用继续试除,直接利用保存的值即可。

    不过这样优化之后耗时可能依然很长(N=3e8时在我的笔记本上耗时约35分钟),所以我们还需要一点“黑科技”——多线程。

    多线程的思想就是把一个大任务分割成若干个小任务,然后让它们同时进行。

    对于本题,我们可以在预处理g(1)~g(N)之后,将剩余的部分(N+1 ~ 2e9)分割成若干块,然后让多个线程分别处理。

    然而有个麻烦,就是用多线程处理的话,计算g(X)时我们并不能知道g(1)~g(X-1)的最大值是多少。

    对策:预处理时我们可以得出g(1)~g(N)的最大值M,然后在处理剩余部分时,将所有满足g(X)>M的值X保存到数组vec,其余的值丢弃(绝大多数都可以被丢掉)。然后在vec中筛选反质数。

    打表程序如下(clang++ -std=c++14 -O3编译,在我的笔记本上预处理部分用了60s,多线程部分用了500s,加起来不到10分钟):

      1 #include <iostream>
      2 #include <cmath>
      3 #include <thread>
      4 #include <mutex>
      5 #include <atomic>
      6 #include <vector>
      7 #include <cstring>
      8 #include <algorithm>
      9 #include <boost/timer.hpp>
     10 
     11 std::vector<int> antiprimes;
     12 
     13 namespace prime
     14 {
     15     const int length = 100'000;
     16     bool primeFlag[length + 1];
     17     std::vector<int> primes;
     18 
     19     void init()
     20     {
     21         std::memset(primeFlag, 1, sizeof(primeFlag));
     22         for (int i = 2; i < 330; i++)
     23         {
     24             if (!primeFlag[i])
     25                 continue;
     26             for (int j = i << 1; j <= length; j += i)
     27                 primeFlag[j] = false;
     28         }
     29         for (int i = 2; i <= length; i++)
     30             if (primeFlag[i])
     31                 primes.push_back(i);
     32     }
     33 }
     34 
     35 namespace pre
     36 {
     37     const int length = 240'000'000;
     38     int factorN[length + 1];
     39     int maxFactorN = 0;
     40 }
     41 
     42 int getFactorN(int x)
     43 {
     44     int ans = 1;
     45     auto sqrtX = (int)std::sqrt(x);
     46     for (int p: prime::primes)
     47     {
     48         if (x == 1 || p > sqrtX)
     49             break;
     50         int cnt = 0;
     51         while (x % p == 0)
     52         {
     53             cnt += 1;
     54             x /= p;
     55         }
     56         if (cnt > 0)
     57         {
     58             ans *= (cnt + 1);
     59             if (x <= pre::length)
     60                 return ans * pre::factorN[x];
     61         }
     62     }
     63     if (x > 1)
     64         ans <<= 1;
     65     return ans;
     66 }
     67 
     68 namespace pre
     69 {
     70     void init()
     71     {
     72         maxFactorN = 0;
     73         for (int i = 1; i <= length; i++)
     74         {
     75             factorN[i] = getFactorN(i);
     76             if (factorN[i] > maxFactorN)
     77             {
     78                 maxFactorN = factorN[i];
     79                 antiprimes.push_back(i);
     80             }
     81         }
     82     }
     83 }
     84 
     85 struct VecNode
     86 {
     87     int val;
     88     int factorN;
     89     bool operator < (const VecNode& rhs) const {
     90         return val < rhs.val;
     91     }
     92 };
     93 std::vector<VecNode> selections;
     94 
     95 std::atomic_int taskN(0);
     96 
     97 //[first, last)
     98 void processEachThread(int first, int last, std::mutex& mtx)
     99 {
    100     boost::timer timer;
    101 
    102     taskN += 1;
    103     mtx.lock();
    104     std::cout << "Thread #" << std::this_thread::get_id() << " is running.
    ";
    105     mtx.unlock();
    106 
    107     for (int cur = first; cur != last; ++cur)
    108     {
    109         int fn = getFactorN(cur);
    110         if (fn > pre::maxFactorN)
    111         {
    112             mtx.lock();
    113             selections.push_back({cur, fn});
    114             mtx.unlock();
    115         }
    116     }
    117     mtx.lock();
    118     std::cout << "Thread #" << std::this_thread::get_id()
    119               << " finished. first = " << first << ", last = " << last
    120               << ", time used = " << timer.elapsed() << " sec.
    ";
    121     mtx.unlock();
    122     taskN -= 1;
    123 }
    124 
    125 void processThreads()
    126 {
    127     constexpr int maxTaskN = 6;
    128     constexpr int taskRangeLength = 20'000'000;
    129 
    130     static_assert((2'000'000'000 - pre::length) % taskRangeLength == 0, "");
    131 
    132     std::vector<std::thread> threads;
    133     std::mutex mtx;
    134     int first(2'000'000'001 - taskRangeLength);
    135     while (first >= pre::length)
    136     {
    137         while (taskN == maxTaskN) {}
    138         threads.emplace_back(processEachThread, first, first + taskRangeLength, std::ref(mtx));
    139         threads.back().detach();
    140         first -= taskRangeLength;
    141     }
    142     while (taskN > 0) {}
    143 }
    144 
    145 void pickSelections()
    146 {
    147     std::sort(selections.begin(), selections.end());
    148     int maxFactorN = pre::maxFactorN;
    149     for (auto node: selections)
    150     {
    151         if (node.factorN <= maxFactorN)
    152             continue;
    153         antiprimes.push_back(node.val);
    154         maxFactorN = node.factorN;
    155     }
    156 }
    157 
    158 int main()
    159 {
    160     boost::timer timer;
    161 
    162     prime::init();
    163     pre::init();
    164     std::cout << "Initialization finished. Time used: " << timer.elapsed() << " sec.
    ";
    165 
    166     timer.restart();
    167     processThreads();
    168     pickSelections();
    169     std::cout << "Process finished. Time used: " << timer.elapsed() << " sec.
    ";
    170 
    171     std::cout << "const int antiprimes[] = {";
    172     for (int x: antiprimes)
    173     {
    174         if (x > 1)
    175             std::cout << ", ";
    176         std::cout << x;
    177     }
    178     std::cout << "};";
    179 
    180     return 0;
    181 }
  • 相关阅读:
    计算机网络学习笔记——计算机网络概述
    基础续一
    Python基础一
    linux lvm的操作手册_pvcreate_vgcreate_lvcreate_相关
    Oracle Linux 挂载存储
    MegaCLI SAS RAID Management Tool
    DELL RACADM 批量升级戴尔IDRAC固件
    LSI MegaCli 命令使用4
    LSI MegaCli 命令使用2
    LSI MegaCl i命令使用1
  • 原文地址:https://www.cnblogs.com/Onlynagesha/p/8584079.html
Copyright © 2011-2022 走看看