codility上的问题 11 Kappa 2011

题目大意: 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;
}
       


你可能感兴趣的:(gcd,codility)