題意:給你一個大整數X的素因子分解形式,每一個因子不超過m。問你可否找到兩個數n,k,k<=n<=m,使得C(n,k)=X。ios
不妨取對數,把乘法轉換成加法。枚舉n,而後去找最大的k(<=n/2),使得ln(C(n,k))<=ln(X),而後用哈希去驗證是否剛好等於ln(X)。c++
因爲n和k有單調性,因此枚舉實際上是O(m)。spa
媽的這個哈希思想賊巧妙啊,由於對數使得精度爆炸,因此不妨同步弄個哈希值,來判相等。orm
opencup的標程:blog
#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"; } } }