题目大意: N组宇航员,每组有若干人,现在要从每组选出若干人,问有多少种方法。
N [1..1000]
T 每组的人数 [1..10^6]
D 要选得人数[1..10^6] 且 T[i] >= D[i]
结果对 1410000017取模。
要求复杂度 时间 O(max(T)*log(max(T))+N), 空间 O(N+max(T))。
分析: 我觉得他要求的复杂度很诡异…… 还有+N什么的 还有 那个我是不是可以把那个去模的数当常数。。。这个常数可是比max(T)还大呢。这个题就是C(m,n)连乘。发现那个取模的数恰好是质数,我们可以用rev(x) = powder(x, p - 2),即求逆元来表示倒数,用乘法就没除法了…… 当然也可以用extend_gcd来求,那样恐怕有log(max(T))了。我现在的方法有个logM...不知道能不能当常数。就是C(m,n) = m! * rev(n!) * rev((m - n)!) 阶乘maxT,我们可以直接打表,逆元用到的时候再求,也就求N次……我抛开那个诡异的复杂度了。。。
代码:
// you can also use includes, for example:
// #include <algorithm>
const int M = 1410000017;
int mul(long long x,long long y) {
return x * y % M;
}
int rev(int x) {
int i,r = 1;
for (i = M - 2, r = 1; i; i >>= 1) {
if (i & 1) {
r = mul(r, x);
}
x = mul(x, x);
}
return r;
}
int solution(const vector<int> &T, const vector<int> &D) {
// write your code here...
int n = T.size(), m, i, answer = 1;
for (i = m = 0; i < n; ++i) {
if (m < T[i]) {
m = T[i];
}
}
vector<int> f,rf;
f.resize(m + 1);
rf.resize(m + 1, 0);
for (i = f[0] = rf[0] = 1; i <= m; ++i) {
f[i] = mul(f[i - 1], i);
}
for (i = 0; i < n; ++i) {
if (rf[D[i]] == 0) {
rf[D[i]] = rev(f[D[i]]);
}
if (rf[T[i] - D[i]] == 0) {
rf[T[i] - D[i]] = rev(f[T[i] - D[i]]);
}
answer = mul(mul(answer, f[T[i]]), mul(rf[D[i]], rf[T[i] - D[i]]));
}
return answer;
}
本文探讨了一种组合数学问题的高效求解方法,通过利用阶乘和逆元的概念,结合快速幂运算,在限定的时间复杂度内实现了组合数的计算,并提供了一段具体的C++实现代码。
932

被折叠的 条评论
为什么被折叠?



