zoukankan      html  css  js  c++  java
  • 【取对数】【哈希】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
    ";
          cout << n << ' ' << k << '
    ';
        } else {
          cout << "NO
    ";
        }
      }
    }
  • 相关阅读:
    Java集合(二)-Set集合
    Java集合类
    Java构造器和初始化块
    学习OpenStack-Neutron网络服务
    Error response from daemon: Get https://index.docker.io/v1/search?q=tomcat&n=25: net/http: TLS handshake timeout
    学习OpenStack-Nova计算服务
    学习OpenStack-Glance组件部署
    报错:rsync同步报错
    报错:创建nginx镜像时出现报错
    报错:重启Docker报错如何解决
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/8849403.html
Copyright © 2011-2022 走看看