Cod sursa(job #3340497)

Utilizator BuzdiBuzdugan Rares Andrei Buzdi Data 14 februarie 2026 17:18:24
Problema Cowfood Scor 60
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.14 kb
#include <bits/stdc++.h>
#define ll long long

using namespace std;

ifstream fin("cowfood.in");
ofstream fout("cowfood.out");

const int NMAX = 20;
const int KMAX = 30;
const int SMAX = 20000;
const int MOD = 3210121;

int k, s, n, answer;
int a[NMAX + 1][KMAX + 1];
int maxi[KMAX + 1];
int fact[SMAX + 50], invfact[SMAX + 50];

int power(int base, int exp) {
    int res = 1;
    while(exp) {
        if(exp % 2 == 1) res = (ll)res * base % MOD;
        base = (ll)base * base % MOD;
        exp /= 2;
    }
    return res;
}

int combinari(int nn, int kk) {
    if(nn < 0 || kk < 0 || kk > nn) return 0;
    return (ll)fact[nn] * invfact[kk] % MOD * invfact[nn - kk] % MOD;
}

int main() {
    fin >> k >> s >> n;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= k; j++) {
            fin >> a[i][j];
        }
    }

    fact[0] = 1;
    // We need combinations up to S + K
    int max_fact = s + k + 5;
    for(int i = 1; i <= max_fact; i++) {
        fact[i] = (ll)fact[i - 1] * i % MOD;
    }
    invfact[max_fact] = power(fact[max_fact], MOD - 2);
    for(int i = max_fact - 1; i >= 0; i--) {
        invfact[i] = (ll)invfact[i + 1] * (i + 1) % MOD;
    }

    answer = 0;

    // Start mask from 0 to include the base case
    for(int mask = 0; mask < (1 << n); mask++) {
        fill(maxi + 1, maxi + k + 1, 0); // Corrected to 0

        for(int i = 1; i <= n; i++) {
            if((mask >> (i - 1)) & 1) {
                for(int j = 1; j <= k; j++) {
                    maxi[j] = max(maxi[j], a[i][j]);
                }
            }
        }

        int sum_here = 0;
        for(int j = 1; j <= k; j++) {
            sum_here += maxi[j];
        }

        // Must prevent negative parameters in combinari
        if(sum_here <= s) {
            int ways = combinari(s - sum_here + k, k); // Fixed to 'k'
            int sign = (__builtin_popcount(mask) % 2 == 1 ? -1 : 1);
            answer = ((ll)answer + sign * ways % MOD + MOD) % MOD;
        }
    }

    // --- SUBTRACT INVALID MIXTURES (< 2 non-zero quantities) ---

    // 1. Check the mixture with exactly 0 quantities (all 0s)
    bool ok0 = true;
    for(int i = 1; i <= n; i++) {
        bool all_zero = true;
        for(int j = 1; j <= k; j++) {
            if(a[i][j] > 0) all_zero = false;
        }
        if(all_zero) { ok0 = false; break; } // Banned by this experiment
    }
    if(ok0) answer = (answer - 1 + MOD) % MOD;

    // 2. Check mixtures with exactly 1 non-zero quantity
    for(int j = 1; j <= k; j++) {
        int limit = s; // Maximum valid amount for herb j
        for(int i = 1; i <= n; i++) {
            bool strict_others = true;
            for(int m = 1; m <= k; m++) {
                if(m != j && a[i][m] > 0) strict_others = false;
            }
            // If the failed experiment only relies on herb j, it caps our limit
            if(strict_others) {
                limit = min(limit, a[i][j] - 1);
            }
        }
        if(limit > 0) {
            answer = (answer - limit + MOD) % MOD;
        }
    }

    fout << answer << '\n';
    return 0;
}