cjb-poi2010divinedivisor1

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
#include <cmath>
#include <numeric>
#include <cassert>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
namespace prime {

    using uint128 = __uint128_t;
    using uint64 = unsigned long long;
    using int64 = long long;
    using uint32 = unsigned int;
    using pii = std::pair<uint64, uint32>;

    inline uint64 sqr(uint64 x) { return x * x; }
    inline uint32 isqrt(uint64 x) { return sqrtl(x); }
    inline uint32 ctz(uint64 x) { return __builtin_ctzll(x); }

    template <typename word>
    word gcd(word a, word b) {
      while (b) { word t = a % b; a = b; b = t; }
      return a;
    }

    template <typename word, typename dword, typename sword>
    struct Mod {
      Mod(): x(0) {}
      Mod(word _x): x(init(_x)) {}
      bool operator == (const Mod& rhs) const { return x == rhs.x; }
      bool operator != (const Mod& rhs) const { return x != rhs.x; }
      Mod& operator += (const Mod& rhs) { if ((x += rhs.x) >= mod) x -= mod; return *this; }
      Mod& operator -= (const Mod& rhs) { if (sword(x -= rhs.x) < 0) x += mod; return *this; }
      Mod& operator *= (const Mod& rhs) { x = reduce(dword(x) * rhs.x); return *this; }
      Mod operator + (const Mod &rhs) const { return Mod(*this) += rhs; }
      Mod operator - (const Mod &rhs) const { return Mod(*this) -= rhs; }
      Mod operator * (const Mod &rhs) const { return Mod(*this) *= rhs; }
      Mod operator - () const { return Mod() - *this; }
      Mod pow(uint64 e) const {
        Mod ret(1);
        for (Mod base = *this; e; e >>= 1, base *= base) {
          if (e & 1) ret *= base;
        }
        return ret;
      }
      word get() const { return reduce(x); }
      static constexpr int word_bits = sizeof(word) * 8;
      static word modulus() { return mod; }
      static word init(word w) { return reduce(dword(w) * r2); }
      static void set_mod(word m) { mod = m, inv = mul_inv(mod), r2 = -dword(mod) % mod; }
      static word reduce(dword x) {
        word y = word(x >> word_bits) - word((dword(word(x) * inv) * mod) >> word_bits);
        return sword(y) < 0 ? y + mod : y;
      }
      static word mul_inv(word n, int e = 6, word x = 1) {
        return !e ? x : mul_inv(n, e - 1, x * (2 - x * n));
      }
      static word mod, inv, r2;

      word x;
    };

    using Mod64 = Mod<uint64, uint128, int64>;
    using Mod32 = Mod<uint32, uint64, int>;
    template <> uint64 Mod64::mod = 0;
    template <> uint64 Mod64::inv = 0;
    template <> uint64 Mod64::r2 = 0;
    template <> uint32 Mod32::mod = 0;
    template <> uint32 Mod32::inv = 0;
    template <> uint32 Mod32::r2 = 0;

    template <class word, class mod>
    bool composite(word n, const uint32* bases, int m) {
      mod::set_mod(n);
      int s = __builtin_ctzll(n - 1);
      word d = (n - 1) >> s;
      mod one{1}, minus_one{n - 1};
      for (int i = 0, j; i < m; ++i) {
        mod a = mod(bases[i]).pow(d);
        if (a == one || a == minus_one) continue;
        for (j = s - 1; j > 0; --j) {
          if ((a *= a) == minus_one) break;
        }
        if (j == 0) return true;
      }
      return false;
    }

    bool is_prime(uint64 n) { // reference: http://miller-rabin.appspot.com
      assert(n < (uint64(1) << 63));
      static const uint32 bases[][7] = {
        {2, 3},
        {2, 299417},
        {2, 7, 61},
        {15, 176006322, uint32(4221622697)},
        {2, 2570940, 211991001, uint32(3749873356)},
        {2, 2570940, 880937, 610386380, uint32(4130785767)},
        {2, 325, 9375, 28178, 450775, 9780504, 1795265022}
      };
      if (n <= 1) return false;
      if (!(n & 1)) return n == 2;
      if (n <= 8) return true;
      int x = 6, y = 7;
      if (n < 1373653) x = 0, y = 2;
      else if (n < 19471033) x = 1, y = 2;
      else if (n < 4759123141) x = 2, y = 3;
      else if (n < 154639673381) x = y = 3;
      else if (n < 47636622961201) x = y = 4;
      else if (n < 3770579582154547) x = y = 5;
      if (n < (uint32(1) << 31)) {
        return !composite<uint32, Mod32>(n, bases[x], y);
      } else if (n < (uint64(1) << 63)) {
        return !composite<uint64, Mod64>(n, bases[x], y);
      }
      return true;
    }

    struct ExactDiv {
      ExactDiv() {}
      ExactDiv(uint64 n) : n(n), i(Mod64::mul_inv(n)), t(uint64(-1) / n) {}
      friend uint64 operator / (uint64 n, ExactDiv d) { return n * d.i; };
      bool divide(uint64 n) { return n / *this <= t; }
      uint64 n, i, t;
    };

    std::vector<ExactDiv> primes;

    void init(uint32 n) {
      uint32 sqrt_n = sqrt(n);
      std::vector<bool> is_prime(n + 1, 1);
      primes.clear();
      for (uint32 i = 2; i <= sqrt_n; ++i) if (is_prime[i]) {
        if (i != 2) primes.push_back(ExactDiv(i));
        for (uint32 j = i * i; j <= n; j += i) is_prime[j] =  0;
      }
    }

    template <typename word, typename mod>
    word brent(word n, word c) { // n must be composite and odd.
      const uint64 s = 256;
      mod::set_mod(n);
      const mod one = mod(1), mc = mod(c);
      mod y = one;
      for (uint64 l = 1; ; l <<= 1) {
        auto x = y;
        for (int i = 0; i < (int)l; ++i) y = y * y + mc;
        mod p = one;
        for (int k = 0; k < (int)l; k += s) {
          auto sy = y;
          for (int i = 0; i < (int)std::min(s, l - k); ++i) {
            y = y * y + mc;
            p *= y - x;
          }
          word g = gcd(n, p.x);
          if (g == 1) continue;
          if (g == n) for (g = 1, y = sy; g == 1; ) {
            y = y * y + mc, g = gcd(n, (y - x).x);
          }
          return g;
        }
      }
    }

    uint64 brent(uint64 n, uint64 c) {
      if (n < (uint32(1) << 31)) {
        return brent<uint32, Mod32>(n, c);
      } else if (n < (uint64(1) << 63)) {
        return brent<uint64, Mod64>(n, c);
      }
      return 0;
    }

    std::vector<pii> factors(uint64 n) {
      assert(n < (uint64(1) << 63));
      if (n <= 1) return {};
      std::vector<pii> ret;
      uint32 v = sqrtl(n);
      if (uint64(v) * v == n) {
        ret = factors(v);
        for (auto &&e: ret) e.second *= 2;
        return ret;
      }
      v = cbrtl(n);
      if (uint64(v) * v * v == n) {
        ret = factors(v);
        for (auto &&e: ret) e.second *= 3;
        return ret;
      }
      if (!(n & 1)) {
        uint32 e = __builtin_ctzll(n);
        ret.emplace_back(2, e);
        n >>= e;
      }
      uint64 lim = sqr(primes.back().n);
      for (auto &&p: primes) {
        if (sqr(p.n) > n) break;
        if (p.divide(n)) {
          uint32 e = 1; n = n / p;
          while (p.divide(n)) n = n / p, e++;
          ret.emplace_back(p.n, e);
        }
      }

      uint32 s = ret.size();
      while (n > lim && !is_prime(n)) {
        for (uint64 c = 1; ; ++c) {
          uint64 p = brent(n, c);
          if (!is_prime(p)) continue;
          uint32 e = 1; n /= p;
          while (n % p == 0) n /= p, e += 1;
          ret.emplace_back(p, e);
          break;
        }
      }
      if (n > 1) ret.emplace_back(n, 1);
      if (ret.size() - s >= 2) sort(ret.begin() + s, ret.end());
      return ret;
    }
}
map<unsigned long long,unsigned int> dic;
int n;
struct Int
{
    int a[1000];
    int tot;
    static const int mob=1000000000;
    Int():a(),tot(){a[0]=1;}
    Int& operator <<= (int x)
    {
        while(x--)
        {
            for(int i=0;i<=tot;++i)
            a[i]<<=1;
            for(int i=0;i<=tot;++i)
            if(a[i]>=mob)
            {
                a[i+1]+=a[i]/mob;
                a[i]%=mob;
            }
            if(a[tot+1]) ++tot;
        }
        return *this;
    }
    void print()
    {
        --a[0];
        printf("%d",a[tot]);
        for(int i=tot-1;~i;--i)
        printf("%09d",a[i]);
    }
}tt;
int main()
{
    cin>>n;
    dic.clear();
    prime::init(1000000);
    for(int i=1;i<=n;i++)
    {
        unsigned long long x; cin>>x;
        auto q = prime::factors(x);
        for(auto p:q)dic[p.first]+=p.second;
    }
    unsigned long long ans=0;
    unsigned int cnt=0;
    for(auto p:dic)
        if (p.second>ans)ans=p.second,cnt=1;
        else if (p.second==ans)cnt++;
    cout<<ans<<endl;
    tt<<=cnt;
    tt.print(); puts("");
    return 0;
}
}}}
#include <cmath>
#include <numeric>
#include <cassert>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
namespace prime {
    using uint128 = __uint128_t;
    using uint64 = unsigned long long;
    using int64 = long long;
    using uint32 = unsigned int;
    using pii = std::pair<uint64, uint32>;
    inline uint64 sqr(uint64 x) { return x * x; }
    inline uint32 isqrt(uint64 x) { return sqrtl(x); }
    inline uint32 ctz(uint64 x) { return __builtin_ctzll(x); }
    template <typename word>
    word gcd(word a, word b) {
      while (b) { word t = a % b; a = b; b = t; }
      return a;
    }
    template <typename word, typename dword, typename sword>
    struct Mod {
      Mod(): x(0) {}
      Mod(word _x): x(init(_x)) {}
      bool operator == (const Mod& rhs) const { return x == rhs.x; }
      bool operator != (const Mod& rhs) const { return x != rhs.x; }
      Mod& operator += (const Mod& rhs) { if ((x += rhs.x) >= mod) x -= mod; return *this; }
      Mod& operator -= (const Mod& rhs) { if (sword(x -= rhs.x) < 0) x += mod; return *this; }
      Mod& operator *= (const Mod& rhs) { x = reduce(dword(x) * rhs.x); return *this; }
      Mod operator + (const Mod &rhs) const { return Mod(*this) += rhs; }
      Mod operator - (const Mod &rhs) const { return Mod(*this) -= rhs; }
      Mod operator * (const Mod &rhs) const { return Mod(*this) *= rhs; }
      Mod operator - () const { return Mod() - *this; }
      Mod pow(uint64 e) const {
        Mod ret(1);
        for (Mod base = *this; e; e >>= 1, base *= base) {
          if (e & 1) ret *= base;
        }
        return ret;
      }
      word get() const { return reduce(x); }
      static constexpr int word_bits = sizeof(word) * 8;
      static word modulus() { return mod; }
      static word init(word w) { return reduce(dword(w) * r2); }
      static void set_mod(word m) { mod = m, inv = mul_inv(mod), r2 = -dword(mod) % mod; }
      static word reduce(dword x) {
        word y = word(x >> word_bits) - word((dword(word(x) * inv) * mod) >> word_bits);
        return sword(y) < 0 ? y + mod : y;
      }
      static word mul_inv(word n, int e = 6, word x = 1) {
        return !e ? x : mul_inv(n, e - 1, x * (2 - x * n));
      }
      static word mod, inv, r2;
      word x;
    };
    using Mod64 = Mod<uint64, uint128, int64>;
    using Mod32 = Mod<uint32, uint64, int>;
    template <> uint64 Mod64::mod = 0;
    template <> uint64 Mod64::inv = 0;
    template <> uint64 Mod64::r2 = 0;
    template <> uint32 Mod32::mod = 0;
    template <> uint32 Mod32::inv = 0;
    template <> uint32 Mod32::r2 = 0;
    template <class word, class mod>
    bool composite(word n, const uint32* bases, int m) {
      mod::set_mod(n);
      int s = __builtin_ctzll(n - 1);
      word d = (n - 1) >> s;
      mod one{1}, minus_one{n - 1};
      for (int i = 0, j; i < m; ++i) {
        mod a = mod(bases[i]).pow(d);
        if (a == one || a == minus_one) continue;
        for (j = s - 1; j > 0; --j) {
          if ((a *= a) == minus_one) break;
        }
        if (j == 0) return true;
      }
      return false;
    }
    bool is_prime(uint64 n) { // reference: http://miller-rabin.appspot.com
      assert(n < (uint64(1) << 63));
      static const uint32 bases[][7] = {
        {2, 3},
        {2, 299417},
        {2, 7, 61},
        {15, 176006322, uint32(4221622697)},
        {2, 2570940, 211991001, uint32(3749873356)},
        {2, 2570940, 880937, 610386380, uint32(4130785767)},
        {2, 325, 9375, 28178, 450775, 9780504, 1795265022}
      };
      if (n <= 1) return false;
      if (!(n & 1)) return n == 2;
      if (n <= 8) return true;
      int x = 6, y = 7;
      if (n < 1373653) x = 0, y = 2;
      else if (n < 19471033) x = 1, y = 2;
      else if (n < 4759123141) x = 2, y = 3;
      else if (n < 154639673381) x = y = 3;
      else if (n < 47636622961201) x = y = 4;
      else if (n < 3770579582154547) x = y = 5;
      if (n < (uint32(1) << 31)) {
        return !composite<uint32, Mod32>(n, bases[x], y);
      } else if (n < (uint64(1) << 63)) {
        return !composite<uint64, Mod64>(n, bases[x], y);
      }
      return true;
    }
    struct ExactDiv {
      ExactDiv() {}
      ExactDiv(uint64 n) : n(n), i(Mod64::mul_inv(n)), t(uint64(-1) / n) {}
      friend uint64 operator / (uint64 n, ExactDiv d) { return n * d.i; };
      bool divide(uint64 n) { return n / *this <= t; }
      uint64 n, i, t;
    };
    std::vector<ExactDiv> primes;
    void init(uint32 n) {
      uint32 sqrt_n = sqrt(n);
      std::vector<bool> is_prime(n + 1, 1);
      primes.clear();
      for (uint32 i = 2; i <= sqrt_n; ++i) if (is_prime[i]) {
        if (i != 2) primes.push_back(ExactDiv(i));
        for (uint32 j = i * i; j <= n; j += i) is_prime[j] =  0;
      }
    }
    template <typename word, typename mod>
    word brent(word n, word c) { // n must be composite and odd.
      const uint64 s = 256;
      mod::set_mod(n);
      const mod one = mod(1), mc = mod(c);
      mod y = one;
      for (uint64 l = 1; ; l <<= 1) {
        auto x = y;
        for (int i = 0; i < (int)l; ++i) y = y * y + mc;
        mod p = one;
        for (int k = 0; k < (int)l; k += s) {
          auto sy = y;
          for (int i = 0; i < (int)std::min(s, l - k); ++i) {
            y = y * y + mc;
            p *= y - x;
          }
          word g = gcd(n, p.x);
          if (g == 1) continue;
          if (g == n) for (g = 1, y = sy; g == 1; ) {
            y = y * y + mc, g = gcd(n, (y - x).x);
          }
          return g;
        }
      }
    }
    uint64 brent(uint64 n, uint64 c) {
      if (n < (uint32(1) << 31)) {
        return brent<uint32, Mod32>(n, c);
      } else if (n < (uint64(1) << 63)) {
        return brent<uint64, Mod64>(n, c);
      }
      return 0;
    }
    std::vector<pii> factors(uint64 n) {
      assert(n < (uint64(1) << 63));
      if (n <= 1) return {};
      std::vector<pii> ret;
      uint32 v = sqrtl(n);
      if (uint64(v) * v == n) {
        ret = factors(v);
        for (auto &&e: ret) e.second *= 2;
        return ret;
      }
      v = cbrtl(n);
      if (uint64(v) * v * v == n) {
        ret = factors(v);
        for (auto &&e: ret) e.second *= 3;
        return ret;
      }
      if (!(n & 1)) {
        uint32 e = __builtin_ctzll(n);
        ret.emplace_back(2, e);
        n >>= e;
      }
      uint64 lim = sqr(primes.back().n);
      for (auto &&p: primes) {
        if (sqr(p.n) > n) break;
        if (p.divide(n)) {
          uint32 e = 1; n = n / p;
          while (p.divide(n)) n = n / p, e++;
          ret.emplace_back(p.n, e);
        }
      }
      uint32 s = ret.size();
      while (n > lim && !is_prime(n)) {
        for (uint64 c = 1; ; ++c) {
          uint64 p = brent(n, c);
          if (!is_prime(p)) continue;
          uint32 e = 1; n /= p;
          while (n % p == 0) n /= p, e += 1;
          ret.emplace_back(p, e);
          break;
        }
      }
      if (n > 1) ret.emplace_back(n, 1);
      if (ret.size() - s >= 2) sort(ret.begin() + s, ret.end());
      return ret;
    }
}
map<unsigned long long,unsigned int> dic;
int n;
struct Int
{
    int a[1000];
    int tot;
    static const int mob=1000000000;
    Int():a(),tot(){a[0]=1;}
    Int& operator <<= (int x)
    {
        while(x--)
        {
            for(int i=0;i<=tot;++i)
            a[i]<<=1;
            for(int i=0;i<=tot;++i)
            if(a[i]>=mob)
            {
                a[i+1]+=a[i]/mob;
                a[i]%=mob;
            }
            if(a[tot+1]) ++tot;
        }
        return *this;
    }
    void print()
    {
        --a[0];
        printf("%d",a[tot]);
        for(int i=tot-1;~i;--i)
        printf("%09d",a[i]);
    }
}tt;
int main()
{
    cin>>n;
    dic.clear();
    prime::init(1000000);
    for(int i=1;i<=n;i++)
    {
        unsigned long long x; cin>>x;
        auto q = prime::factors(x);
        for(auto p:q)dic[p.first]+=p.second;
    }
    unsigned long long ans=0;
    unsigned int cnt=0;
    for(auto p:dic)
        if (p.second>ans)ans=p.second,cnt=1;
        else if (p.second==ans)cnt++;
    cout<<ans<<endl;
    tt<<=cnt;
    tt.print(); puts("");
    return 0;
}