题意:给你一个大整数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 "; } } }