CSES - Datatähti 2025 alku - Results
Submission details
Task:Kortit II
Sender:Pikaksi
Submission time:2024-10-31 17:56:36 +0200
Language:C++ (C++20)
Status:READY
Result:100
Feedback
groupverdictscore
#1ACCEPTED3
#2ACCEPTED5
#3ACCEPTED26
#4ACCEPTED28
#5ACCEPTED38
Test results
testverdicttimegroup
#1ACCEPTED0.05 s1, 2, 3, 4, 5details
#2ACCEPTED0.05 s2, 3, 4, 5details
#3ACCEPTED0.05 s3, 4, 5details
#4ACCEPTED0.05 s4, 5details
#5ACCEPTED0.11 s5details
#6ACCEPTED0.13 s5details

Code

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
 
const ll ansMod = 1000000007;

const int cacheSize = 2002;
ll aCache[cacheSize][cacheSize];
ll binomCache[cacheSize][cacheSize];

// a(n+1, r) = r*a(n, r) + (n+1-r)*a(n, r-1) + n*a(n-1, r-1)
ll a(ll n, ll r)
{
    if (r >= n) {
        return 0;
    }
    if (n - 1 == r || r == 1) {
        return 1;
    }

    n -= 1;
    ll cacheAns = aCache[n][r];
    if (cacheAns != -1) {
        return cacheAns;
    }

    ll ans =((r * a(n, r)) % ansMod)
        + (((n + 1 - r) * a(n, r - 1)) % ansMod)
        + ((n * a(n - 1, r - 1)) % ansMod) % ansMod;
    
    aCache[n][r] = ans;
    return ans;
}

ll binomRecursive(ll n, ll k)
{
    if (k > n) {
        return 0;
    }
    if (k == 0 || k == n) {
        return 1;
    }

    ll cacheAns = binomCache[n][k];
    if (cacheAns != -1) {
        return cacheAns;
    }
    ll ans = ((binomRecursive(n - 1, k - 1) % ansMod) + (binomRecursive(n - 1, k) % ansMod)) % ansMod;
    binomCache[n][k] = ans;
    return ans;
}

ll factorial(ll a)
{
    if (a == 0) {
        return 1;
    }

    ll b = a;
    for (int i = 2; i < b; i++) {
        a = a * i % ansMod;
    }
    return a;
}

void SolveCase(int cards, int p1, int p2)
{
    int draws = cards - p1 - p2;
 
    string ans1;
    string ans2;
 
    if (p1 + p2 > cards) {
        cout << "0\n";
        return;
    }
 
    if ((p1 > 0 && p2 == 0) || (p2 > 0 && p1 == 0)) {
        cout << "0\n";
        return;
    }
 
    ll ans = binomRecursive(cards, draws);
    //cout << binomRecursive(cards, draws) << "\n";
    ans %= ansMod;

    ans *= ans;
    ans %= ansMod;

    ans *= factorial(draws);
    //cout << factorial(draws) << "\n";
    ans %= ansMod;

    ans *= factorial(p1 + p2);
    //cout << factorial(p1 + p2) << "\n";
    ans %= ansMod;

    if (p1 != 0 || p2 != 0) {
        ll bigger = max(p1, p2);
        ll smaller = min(p1, p2);
        ans *= a(bigger + smaller, smaller);
    }
    //cout << p1 << " " << p2 << " " << a(bigger + smaller, smaller) << "\n";
    ans %= ansMod;
 
    cout << ans << "\n";
}
 
 
int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    for (int x = 0; x < cacheSize; x++) {
        for (int y = 0; y < cacheSize; y++) {
            aCache[x][y] = -1;
            binomCache[x][y] = -1;
        }
    }
 
    /*for (int i = 0; i < C; i++) {
        comparison[i] = i + 1;
    }
    int test[C];
    for (int i = 0; i < C; i++) {
        test[i] = 0;
    }
    testBruteForce(test);
    cout << globalCount << "\n";
    cout << playerWinCombinations(g_p1, g_p2) << "\n";
    return 0;*/
    //SolveCase(9, 3, 5);
    //return 0;
 
    int n;
    cin >> n;
    vector<int> input1, input2, input3;
 
    for (int i = 0; i < n; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        input1.push_back(a);
        input2.push_back(b);
        input3.push_back(c);
    }
 
    for (int i = 0; i < n; i++) {
        SolveCase(input1[i], input2[i], input3[i]);
    }
}

/*
draw possibilities:
cards
draws
 
location combinations of victories and draws:
    (draws)_cards
 
Combinations for draws not placement:
    draws!
 
Combinations for victory positions in list:
    (victories)_p1
 
Combinations for ordering p1 and p2 wins seperately wins:
    p1! * p2!
 
current best: binom(c; d)*binom(c; d)*d!*binom(p1+p2;p1)*p1!*p2!*binom(p1+p2;p1)
better:
binom(c; d)*binom(c; d)*d!*(p1+p2)!*3361*/

 
/*const int g_p1 = 7;
const int g_p2 = 4;
const int C = g_p1 + g_p2;
int comparison[C];
int globalCount = 0;
 
// T\left(n{,}k\right)=\sum_{j=0}^n\binom{-j-1}{-n-1}\cdot eulerian1(j{,}k) 
// T\left(n{,}k\right)=\sum_{u=0}^k(-1)^u\cdot\binom{n+1}{u}\cdot(k+1-u)^n 
// T\left(n{,}k\right)=\sum_{j=0}^n\left(\binom{-j-1}{-n-1}\cdot\sum_{u=0}^k\left((-1)^u\cdot\binom{j+1}{u}\cdot(k+1-u)^n\right)\right) 
 
ll factorial(ll a)
{
    if (a == 0) {
        return 1;
    }
 
    ll negative = 1;
    if (a < 0) {
        if (a & 1) {
            negative = -1;
        }
        a *= -1;
    }
 
    ll aCopy = a;
    for (ll i = 1; i < aCopy; i++) {
        a *= i;
    }
    return a * negative;
}
 
ll binomial(ll a, ll b)
{
    if (a < 0) {
        if (b >= 0) {
            return pow(-1, b) * binomial(b - a - 1, b);
        }
        return pow(-1, a - b) * binomial(-b - 1, a - b);
    }
 
    ll a1 = factorial(a);
    ll a2 = factorial(b);
    ll a3 = factorial(a - b);
    //cout << "binom a1 " << a1 << " a2 " << a2 << " a3 " << a3 << "\n";
 
    return a1 / (a2 * a3);
}

ll BinomialCoeffient(ll n, ll k)
{
    if (k > n)
        return 0;

    ll c = n;
    for (ll i = 1; i < k; i++)
    {
        c *= n - i;
        c /= i + 1;
    }
    return c;
}

ll eulerian(ll n, ll k) {
    ll ans = 0;
    for (ll j = 0; j < k + 1; j++) {
        ll loopAns = pow(-1LL, j);
        loopAns *= BinomialCoeffient(n + 1, j) % ansMod;
        loopAns *= pow(k + 1 - j, n);
 
        ans += loopAns;
    }
    return ans;
}
 
ll playerWinCombinations(ll n, ll k)
{
    if (n < 2 || k < 2) {
        return 1;
    }
    n += k - 2;
 
    if (k > n) {
        ll temp = n;
        n = k;
        k = temp;
    }
    n += 2;
 
    ll ans = 0;
    for (ll j = 0; j < n + 1; j++) {
 
        ll E1 = eulerian(j, k);
        E1 *= binomial(-j - 1, -n - 1);
        ans += E1;
        ans %= ansMod;
    }
    return ans;
}
 
bool containsNumber(int numbersUsed[C], int number)
{
    for (int i = 0; i < C; i++) {
        if (numbersUsed[i] == number) {
            return true;
        }
    }
    return false;
}
 
void testBruteForce(int numbersUsed[C])
{
    cout << "called with ";
    for (int i = 0; i < C; i++) {
        cout << numbersUsed[i];
    } 
    cout << "\n";
    bool allUsed = true;
    for (int i = 0; i < C; i++) {
        if (numbersUsed[i] == 0) {
            allUsed = false;
 
            for (int newNum = 1; newNum < C + 1; newNum++) {
                if (comparison[i] != newNum && !containsNumber(numbersUsed, newNum)) {
                    numbersUsed[i] = newNum;
                    testBruteForce(numbersUsed);
                }
            }
            numbersUsed[i] = 0;
            break;
        }
    }
    if (!allUsed) {
        return;
    }
    
    int larger = 0, smaller = 0;
    for (int i = 0; i < C; i++) {
        if (numbersUsed[i] < comparison[i]) {
            smaller++;
        }
        else if (numbersUsed[i] > comparison[i]) {
            larger++;
        }
    }
    if (smaller == g_p1 && larger == g_p2) {
        globalCount++;
    }
}*/
 

Test details

Test 1

Group: 1, 2, 3, 4, 5

Verdict: ACCEPTED

input
54
4 4 0
3 1 3
3 2 2
4 0 4
...

correct output
0
0
0
0
0
...

user output
0
0
0
0
0
...

Test 2

Group: 2, 3, 4, 5

Verdict: ACCEPTED

input
284
6 1 0
5 0 2
7 1 5
7 7 5
...

correct output
0
0
35280
0
36720
...

user output
0
0
35280
0
36720
...

Test 3

Group: 3, 4, 5

Verdict: ACCEPTED

input
841
19 3 12
19 19 13
19 7 13
20 11 15
...

correct output
40291066
0
0
0
0
...

user output
40291066
0
0
0
0
...

Test 4

Group: 4, 5

Verdict: ACCEPTED

input
1000
15 12 6
7 1 6
44 4 26
6 6 5
...

correct output
0
5040
494558320
0
340694548
...

user output
0
5040
494558320
0
340694548
...

Test 5

Group: 5

Verdict: ACCEPTED

input
1000
892 638 599
966 429 655
1353 576 1140
1403 381 910
...

correct output
0
0
0
249098285
0
...

user output
0
0
0
249098285
0
...

Test 6

Group: 5

Verdict: ACCEPTED

input
1000
2000 1107 508
2000 1372 249
2000 588 65
2000 1739 78
...

correct output
750840601
678722180
744501884
159164549
868115056
...

user output
750840601
678722180
744501884
159164549
868115056
...