Submission #1359792

#TimeUsernameProblemLanguageResultExecution timeMemory
1359792jajceslavMonster-Go (EGOI25_monstergo)C++20
100 / 100
1 ms344 KiB
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define ll long long
#define ull unsigned long long
#define lll __int128_t
#define ulll __uint128_t
#define ld long double
#define lld __float128

#define fi first
#define se second
#define mp make_pair

#define fast ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)

template<typename T>
using V = vector<T>;
template<typename T>
using VV = V<V<T>>;
template<typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template<typename T>
using ordered_multiset = tree<T, null_type, less_equal<T>, rb_tree_tag, tree_order_statistics_node_update>;

template<typename T, typename U>
bool chmax(T &x, U v) {return (v > x)? x=v,1 : 0;}
template<typename T, typename U>
bool chmin(T &x, U v) {return (v < x)? x=v,1 : 0;}

mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937_64 rnd64(chrono::steady_clock::now().time_since_epoch().count());

extern const int MOD;

struct mod
{
    int val;
    mod() : val(0) {}
    mod(ll val) : val(((val % MOD) + MOD) % MOD) {} // fuck c++ modulos

    mod operator+(const mod& a) const { return mod((val + a.val) % MOD); }
    mod operator-(const mod& a) const { return mod((val + MOD - a.val) % MOD); }
    mod operator-() const { return mod((MOD-val) % MOD);}
    mod operator*(const mod& a) const { return mod(((ll)val * a.val) % MOD); }
    template<typename T>
    mod operator^(T power) const {
        mod res = 1, a = val;
        for(; power; power >>= 1, a = a*a) if(power & 1) res = res*a;
        return res;
    }
    mod operator~() const { return *this ^ (MOD-2); }
    mod operator/(const mod& a) const { return *this * (~a); }
    friend istream& operator>>(istream& s, mod& x)  { return s >> x.val, s; }
    friend ostream& operator<<(ostream& s, const mod& x) { return s << x.val, s; }
    operator int() const { return val; }
};

namespace fact
{
    mod *f, *nf;
    void precalc(int n) {
        f = new mod[n+1], nf = new mod[n+1];
        int i;
        for(i = 1, f[0] = 1; i <= n; i++) f[i] = f[i-1]*mod(i);
        for(i = n-1, nf[n] = ~f[n]; i >= 0; i--) nf[i] = nf[i+1]*mod(i+1);
    }

    mod fact(int n) { return f[n]; }
    mod n_fact(int n) { return nf[n]; }
    mod c(int n, int k) { return fact(n) * n_fact(k) * n_fact(n-k); }
};

// #pragma GCC optimize("Ofast")
// #pragma GCC target("avx,avx2,fma")

// #define DEBUG

#ifdef DEBUG

#define _dark "\e[34m"
#define _bright "\e[38;5;220m"
#define _reset "\e[39m\n"

template<typename T, typename = void>
struct is_iterable : std::false_type {};

template<typename T>
struct is_iterable<T, std::void_t<
    decltype(std::begin(std::declval<T>())),
    decltype(std::end(std::declval<T>()))
>> : std::true_type {};

template<typename T>
inline enable_if_t<!is_iterable<T>::value, void>
__print(const T &x) { cerr << _bright << x; }
template<typename T, typename U>
inline void __print(const pair<T,U> &x) {
    cerr << _dark << "(";
    __print(x.fi);
    cerr << _dark << ", ";
    __print(x.se);
    cerr << _dark << ")";
}

template<typename T>
inline void _print_iterable(T begin, T end, bool lines=false);
template<typename T>
inline void _print_set(const T &x) {
    cerr << _dark << "{";
    _print_iterable(x.begin(), x.end());
    cerr << _dark << "}";
}
template<typename T>
inline void _print_list(const T &x) {
    cerr << _dark << "[";
    _print_iterable(x.begin(), x.end());
    cerr << _dark << "]";
}
template<typename T>
inline void _print_map(const T &x);

template<typename T>
inline enable_if_t<is_iterable<T>::value, void> __print(const T &x) { _print_set(x); }
template<typename T>
inline void __print(const vector<T> &x) { _print_list(x); }
template<typename T, typename U>
inline void __print(const map<T, U> &x) { _print_map(x); }
template<typename T, typename U>
inline void __print(const unordered_map<T, U> &x) { _print_map(x); }
template<typename T, typename U>
inline void __print(const gp_hash_table<T, U> &x) { _print_map(x); }
template<typename T, typename U>
inline void __print(const cc_hash_table<T, U> &x) { _print_map(x); }

inline void _print() {}
template<typename T>
inline void _print(const T &x, auto... y) {
    __print(x);
    if(sizeof...(y)) cerr << _dark << ", ";
    _print(y...);
}

template<typename T>
inline void _print_iterable(T begin, T end, bool lines) {
    bool p = 0;
    for(T it = begin; it != end; it++) {
        if(p) cerr << _dark << "," << (lines ? "\n" : " ");
        __print(*it);
        p = 1;
    }
}
template<typename T>
inline void _print_map(const T &x) {
    cerr << _dark << "{";
    bool p = 0;
    for(const auto &i : x) {
        if(p) cerr << _dark << ", ";
        __print(i.fi);
        cerr << _dark << "->";
        __print(i.se);
        p = 1;
    }
    cerr << _dark << "}";
}

template<typename T>
inline void _print_2d(T begin, T end, int size) {
    bool p = 0;
    for(T it = begin; it != end; it++) {
        if(p) cerr << "\n";
        _print_iterable(*it, *it+size);
        p = 1;
    }
}

#define _source source_location::current()
#define debug_pref(name, a...) cerr << _dark << _source.file_name() << ":" << _source.line() << ":" << _source.column() << " " << name << "(" << _bright << #a << _dark << ")";
#define debug(a...) {debug_pref("debug", a); cerr << _dark << " = "; _print(a); cerr << _reset;}
#define debug_1d(begin, end) {debug_pref("debug_1d", begin, end); cerr << _dark << " = ["; _print_iterable(begin, end, false); cerr << _dark << "]" << _reset;}
#define debug_lines(begin, end) {debug_pref("debug_lines", begin, end); cerr << _dark << " = [\n"; _print_iterable(begin, end, true); cerr << _dark << "\n]" << _reset;}
#define debug_2d(begin, n, m) {debug_pref("debug_2d", begin, end); cerr << _dark << " = [\n"; _print_2d(begin, begin+n, m); cerr << _dark << "\n]" << _reset;}

#endif
#ifndef DEBUG
#define debug(a...)
#define debug_1d(begin, end)
#define debug_lines(begin, end)
#define debug_2d(begin, n, m)

#endif

#define mtst int T; cin >> T; for(int test = 0; test < T; test++)

const int MOD = 1e9+7;

/*

What are the conditions for array to be good? 
For every pair of players, there exists a player whos array is a subset of their union

if we split 50 monsters into groups of 6, we can define each player as a pair (i, j)
8 elements, 8 * 7 / 2 = 4*7 = 28 players, not bad, 52 points

*/

struct mve
{
    int size, cnt, sum;
    mve(int size, int cnt, int sum): size(size), cnt(cnt), sum(sum) {}
    mve(): size(0), cnt(0), sum(0) {}
};

mve dp[55][55];

inline ll fct(int n)
{
    ll res = 1;
    for(int i = 2; i <= n; i++)
        res *= i;
    return res;
}

inline ll c(int n, int k)
{
    return fct(n) / (fct(k) * fct(n-k));
}

vector<int> cur;
void rec(int i, int cnt, vector<vector<int> > &ans)
{
    if(i == 0)
    {
        if(cnt == 0)
            ans.push_back(cur);
        return;
    }

    rec(i-1, cnt, ans);
    if(cnt) {
        cur.push_back(i-1);
        rec(i-1, cnt-1, ans);
        cur.pop_back();
    }
}

vector<vector<int> > get_vals(int sz, int cnt)
{
    vector<vector<int> > ans;
    cur.clear();

    rec(cnt / sz, 12/sz, ans);
    return ans;
}

int main()
{
    vector<mve> moves;
    auto sizes = {1, 2, 3, 4, 6};
    for(auto sz : sizes)
    {
        for(int add = 0; add <= 50; add++)
        {
            ll cnt = c(12/sz + add, 12/sz);
            if(cnt > 50 || (12/sz + add) > 50)
                break;
            moves.push_back(mve(sz, (12/sz + add) * sz, cnt));
        }
    }

    debug(moves.size());

    dp[0][0] = mve(-1, -1, -1);
    for(int cnt = 0; cnt < 50; cnt++)
    {
        for(int sum = 0; sum < 50; sum++)
        {
            if(dp[cnt][sum].size == 0)
                continue;
            for(auto mv : moves)
            {
                if(cnt + mv.cnt <= 50 && sum + mv.sum <= 50)
                    dp[cnt + mv.cnt][sum + mv.sum] = mv;
            }
        }
    }


    debug("dp done");
    
    int n; cin >> n;
    debug(n);

    int cnt = 0, sum = n;
    for(int i = 0; i <= 50; i++)
    {
        if(dp[i][sum].size != 0)
        {
            cnt = i;
            break;
        }
    }

    vector<mve> ans_moves;
    while(cnt || sum)
    {
        debug(cnt, sum);
        auto mv = dp[cnt][sum];
        ans_moves.push_back(mv);
        cnt -= mv.cnt;
        sum -= mv.sum;
    }

    int cur = 0;
    vector<vector<int> > ans;
    for(auto mv : ans_moves)
    {
        auto vals = get_vals(mv.size, mv.cnt);
        for(auto vl : vals)
        {
            vector<int> res;
            for(int x : vl)
            {
                for(int i = 0; i < mv.size; i++)
                {
                    res.push_back(cur + x * mv.size + i);
                }
            }
            assert(res.size() == 12);
            ans.push_back(res);
        }
        cur += mv.cnt;
    }
    assert(ans.size() == n);
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < 12; j++)
        {
            cout << ans[i][j] << ' ';
        }
        cout << '\n';
    }
}   

/*

*/
#Result Execution timeMemoryGrader output
Fetching results...