【取对数】【哈希】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem J. Bobby Tables

题意:给你一个大整数X的素因子分解形式,每个因子不超过m。问你能否找到两个数n,k,k<=n<=m,使得C(n,k)=X。

不妨取对数,把乘法转换成加法。枚举n,然后去找最大的k(<=n/2),使得ln(C(n,k))<=ln(X),然后用哈希去验证是否恰好等于ln(X)。

由于n和k有单调性,所以枚举其实是O(m)。

妈的这个哈希思想贼巧妙啊,因为对数使得精度爆炸,所以不妨同步弄个哈希值,来判相等。

opencup的标程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "bits/stdc++.h"
using namespace std;

using UInt = unsigned long long;
using Float = long double;

const int M = 150 * 1000;

Float LogSum[M+1];
UInt Hash[M+1];
UInt HashSum[M+1];

void Init(int m) {
  // LogF
  LogSum[0] = 0.;
  for (int i = 1; i <= m; ++i) {
    LogSum[i] = LogSum[i-1] + log((Float) i);
  }
  
  // Hash, HashF
  std::mt19937 gen;
  uniform_int_distribution<UInt> distr;
  vector<int> sieve(m+1, 0);
  for (int i = 2; i * i <= m; ++i) {
    if (sieve[i] == 0) {
      for (int j = i * i; j <= m; j += i) {
        sieve[j] = i;
      }
    }
  }
  Hash[0] = Hash[1] = 0; 
  for (int i = 2; i <= m; ++i) {
    if (sieve[i] == 0) {
      Hash[i] = distr(gen);
    } else {
      Hash[i] = Hash[i/sieve[i]] + Hash[sieve[i]];
    }
  }
  partial_sum(Hash, Hash + m + 1, HashSum);
}

Float LogBinom(int n, int k) {
  return LogSum[n] - LogSum[n-k] - LogSum[k];
}

UInt HashBinom(int n, int k) {
  return HashSum[n] - HashSum[n-k] - HashSum[k];
}

bool Solve(const vector<int>& factors, int m, int& n, int& k) {
  for (int p : factors) {if (p > m) { return false; }}
  Float log_x = 0;
  UInt hash_x = 0;
  for (int p : factors) { log_x += log((Float) p); hash_x += Hash[p]; }

  //check 
  int b = m;
  for (int a = 0; a <= m; ++a) {
    while (b > 0 && (a + b - 1 > m || LogBinom(a+b-1, a) >= log_x)) { --b; }
    if (b > 0 && HashBinom(a + b - 1, a) == hash_x) {
      n = a + b - 1;
      k = a;
      return true;
    }
    if (a + b <= m && HashBinom(a+b, a) == hash_x) {
      n = a + b;
      k = a;
      return true;
    }
  }
  return false;
}

int main() {
  Init(M);
  ios_base::sync_with_stdio(false);
  int z;
  cin >> z;
  while (z--) {
    int t;
    int m;
    cin >> t >> m;
    vector<int> factors(t);
    for (int i = 0; i < t; ++i) {
      cin >> factors[i];
    }

    //assert(t != 0);
    int n, k;
    if (Solve(factors, m, n, k)) {
      cout << "YES\n";
      cout << n << ' ' << k << '\n';
    } else {
      cout << "NO\n";
    }
  }
}
posted @ 2018-04-15 20:52  AutSky_JadeK  阅读(285)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト