ferinの競プロ帳

競プロについてのメモ

SRM628 div1 easy DivisorsPower

概要

d(n) = (nの正の約数の個数)、h(n) = n^d(n)とする。x = h^-1(n) を求めろ。複数存在する場合は最も小さいものを求めろ。

解法

d(x) として使われうる値は20程度までしか存在しない。d(x)を決め打って、そのd(x)のときh^-1(n)が存在するか考える。nのm乗根を求めたあとd(nのm乗根) == mであるかどうか判定すればよい。nのm乗根は二分探索を用いてO(mlogn)、d(n)はO(sqrt(sqrt(n)))で計算できる。全体で O( max(d(x))(mlogn + sqrt(sqrt(n))) ) で計算できる。
オーバーフローに注意

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<int, int> PII;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define IN(a, b, x) (a<=x&&x<b)
#define MP make_pair
#define PB push_back
const int INF = (1LL<<30);
const ll LLINF = (1LL<<60);
const double PI = 3.14159265359;
const double EPS = 1e-12;
const int MOD = 1000000007;
//#define int ll

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

//二分累乗法 xのe乗
ll binpow(ll x, ll e) {
  ll a = 1, p = x;
  while(e > 0) {
    if(e%2 == 0) {p = (p*p); e /= 2;}
    else {a = (a*p); e--;}
  }
  return a;
}

// nのm乗根 整数でなければ-1 O(mlogn)
ll root(ll n, ll m) {
  ll lb = 1, ub = n;
  while(ub-lb > 1) {
    ll mid = (lb+ub)/2, tmp = mid, prev = 1;
    REP(i, m-1) {
      if(tmp/prev != (tmp*mid)/tmp) {tmp = n+1; break;}
      prev = tmp;
      tmp *= mid;
    }
    if(tmp >= n) ub = mid;
    else lb = mid;
  }
  ll tmp = ub, prev = 1;
  REP(i, m-1) {
    if(tmp/prev != (tmp*ub)/tmp) {tmp = -1; break;}
    prev = tmp;
    tmp *= ub;
  }
  if(tmp == n) return ub;
  return -1;
}

class DivisorsPower {
   public:
   long long findArgument(long long n)
  {
    ll ret = INF;
    FOR(i, 2, 21) {
      ll sq = root(n, i);
      if(sq == -1) continue;
      // d(sq) = i であれば
      ll cnt = 0;
      for(ll k=1; k*k<=sq; ++k) {
        if(sq%k==0) {
          cnt++;
          if(k*k!=sq) {
            cnt++;
          }
        }
      }
      if(cnt == i) chmin(ret, sq);
    }
    return ret==INF ? -1 : ret;
  }
};