Timus[1091. Tmutarakan Exams]

原题地址:Timus[1091. Tmutarakan Exams]

 

输入一对整数K和S,求出由K个互不相等且不大于S的正整数组成的集合的个数N,当N大于10000时,输出10000即可。

想到的解法是去求各个质数的倍数所能组成的集合数,这个就是一个组合数。然后用集合元素个数的加法定理?cardinality of (A union B) = cardinality of (A) + cardinality of (B) - cardinality of (A intesect B)的这个。

用dfs来遍历可能的质数积的组合,代码如下:

#include <iostream>

using namespace std;

int K, S;

const int MAX_N = 9;

bool done;

int primes[MAX_N] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };

int combinations(int k, int n)
{
    if (2 * k > n)
    {
        k = n - k;
    }
    long long x = 1;
    int z = k;
    for (int i = 0; i < k; ++i)
    {
        x *= n - i;
        while (z > 1 && x % z == 0)
        {
            x /= z--;
        }
    }
    return x;
}

int ans = 0;

void dfs(int k, int product, int m)
{
    if (k + 1 != MAX_N && K * product * primes[k + 1] <= S)
    {
        dfs(k + 1, product, m);
    }

    product *= primes[k];
    if (K * product > S)
        return;
    ++m;

    int c = combinations(K, S / product);
    if (c >= 10000)
    {
        ans = 10000;
        done = true;
        return;
    }
    ans += ((m & 1) ? 1 : -1) * c;
    if (ans >= 10000)
    {
        done = true;
    }
    if (!done && k + 1 != MAX_N && K * product * primes[k + 1] <= S)
    {
        dfs(k + 1, product, m);
    }
}

int solve()
{
    done = false;
    dfs(0, 1, 0);
    if (done)
        return 10000;
    return ans;
}

int main()
{
    cin >> K >> S;
    cout << solve() << endl;
    return 0;
}
Solution.

 

posted @ 2018-11-17 14:47  knull  Views(167)  Comments(0)    收藏  举报