Submission #777685

#TimeUsernameProblemLanguageResultExecution timeMemory
777685boris_mihovScales (IOI15_scales)C++17
0 / 100
1091 ms4576 KiB
#include "scales.h"
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cassert>
#include <random>
#include <vector>
#include <map>
#include <set>

typedef long long llong;
const int MAXB = 14349000;
const int N = 6;

struct Permutation
{
    int vals[N];
    Permutation(){}
    Permutation(int _vals[])
    {
        for (int i = 0 ; i < N ; ++i)
        {
            vals[i] = _vals[i];
        }
    }

    int getLightest(int a, int b)
    {
        int value = std::min(vals[a - 1], vals[b - 1]);
        if (vals[a - 1] == value) return a;
        if (vals[b - 1] == value) return b;
    }
    
    int getLightest(int a, int b, int c)
    {
        int value = std::min(std::min(vals[a - 1], vals[b - 1]), vals[c - 1]);
        if (vals[a - 1] == value) return a;
        if (vals[b - 1] == value) return b;
        if (vals[c - 1] == value) return c;
    }
    
    int getHeaviest(int a, int b, int c)
    {
        int value = std::max(std::max(vals[a - 1], vals[b - 1]), vals[c - 1]);
        if (vals[a - 1] == value) return a;
        if (vals[b - 1] == value) return b;
        if (vals[c - 1] == value) return c;
    }

    int getMedian(int a, int b, int c)
    {
        int min = getLightest(a, b, c);
        int max = getHeaviest(a, b, c);
        if (min != a && max != a) return a;
        if (min != b && max != b) return b;
        if (min != c && max != c) return c;
    }

    int getNextLightest(int a, int b, int c, int d)
    {
        if (std::max(std::max(vals[a - 1], vals[b - 1]), std::max(vals[c - 1], vals[d - 1])) == vals[d - 1])
        {
            return getLightest(a, b, c);
        }

        std::vector <int> coins;
        if (vals[a - 1] > vals[d - 1])
        {
            coins.push_back(a);
        }

        if (vals[b - 1] > vals[d - 1])
        {
            coins.push_back(b);
        }

        if (vals[c - 1] > vals[d - 1])
        {
            coins.push_back(c);
        }

        if (coins.size() == 1) return coins[0];
        if (coins.size() == 2) return getLightest(coins[0], coins[1]);
        if (coins.size() == 3) return getLightest(coins[0], coins[1], coins[2]);
    }

    int getRes(int t, int a, int b, int c, int d)
    {
        if (t == 0) return getLightest(a, b, c);
        if (t == 1) return getHeaviest(a, b, c);
        if (t == 2) return getMedian(a, b, c);
        if (t == 3) return getNextLightest(a, b, c, d);
    }

    friend bool operator == (const Permutation &a, const Permutation &b)
    {
        for (int i = 0 ; i < N ; ++i)
        {
            if (a.vals[i] != b.vals[i])
            {
                return false;
            }
        }

        return true;
    }

    friend bool operator < (const Permutation &a, const Permutation &b)
    {
        for (int i = 0 ; i < N ; ++i)
        {
            if (a.vals[i] < b.vals[i]) return true;
            if (a.vals[i] > b.vals[i]) return false;
        }

        return false;
    }
};

struct Mask
{
    std::vector <Permutation> perms;
    std::vector <Mask> split(int t, int a, int b, int c, int d = 0)
    {
        std::vector <Mask> res;
        std::vector <int> perm;
        perm.resize(perms.size(), 0);
        std::iota(perm.begin(), perm.end(), 0);
        std::sort(perm.begin(), perm.end(), [&](int x, int y)
        {
            return perms[x].getRes(t, a, b, c, d) < perms[y].getRes(t, a, b, c, d);
        });

        for (int i = 0 ; i < perms.size() ; ++i)
        {
            if (res.empty() || res.back().perms.back().getRes(t, a, b, c, d) != perms[perm[i]].getRes(t, a, b, c, d))
            {
                Mask newMask;
                res.push_back(newMask);
            }

            res.back().perms.push_back(perms[perm[i]]);
        }

        return res;
    }

    Mask getSplit(int wanted, int t, int a, int b, int c, int d)
    {
        std::vector <Mask> res;
        std::vector <int> perm;
        perm.resize(perms.size(), 0);
        std::iota(perm.begin(), perm.end(), 0);
        std::sort(perm.begin(), perm.end(), [&](int x, int y)
        {
            return perms[x].getRes(t, a, b, c, d) < perms[y].getRes(t, a, b, c, d);
        });

        for (int i = 0 ; i < perms.size() ; ++i)
        {
            if (res.empty() || res.back().perms.back().getRes(t, a, b, c, d) != perms[perm[i]].getRes(t, a, b, c, d))
            {
                Mask newMask;
                res.push_back(newMask);
            }

            res.back().perms.push_back(perms[perm[i]]);
        }

        for (int i = 0 ; i < res.size() ; ++i)
        {
            if (res[i].perms.back().getRes(t, a, b, c, d) == wanted)
            {
                return res[i];
            }
        }
    }

    friend bool operator < (const Mask &a, const Mask &b)
    {
        if (a.perms.size() < b.perms.size()) return true;
        if (a.perms.size() > b.perms.size()) return false;

        for (int i = 0 ; i < a.perms.size() ; ++i)
        {
            if (a.perms[i] < b.perms[i]) return true;
            if (!(a.perms[i] == b.perms[i])) return false;
        }

        return false;
    }
};

struct Operation
{
    int t, a, b, c, d;
    Operation(){}
    Operation(int _t, int _a, int _b, int _c)
    {
        t = _t;
        a = _a;
        b = _b;
        c = _c;
        d = 0;
    }

    Operation(int _t, int _a, int _b, int _c, int _d)
    {
        t = _t;
        a = _a;
        b = _b;
        c = _c;
        d = _d;
    }

    friend bool operator < (const Operation &x, const Operation &y)
    {
        return x.t < y.t || (x.t == y.t && x.a < y.a) || (x.t == y.t && x.a == y.a && x.b < y.b) || (x.t == y.t && x.a == y.a && x.b == y.b && x.c < y.c) || (x.t == y.t && x.a == y.a && x.b == y.b && x.c == y.c && x.d < y.d);
    }
};

const int DP_CONST = 1;
const int T_CONST = 10;

std::map <Mask, int> mem;
std::map <Mask, Operation> next;
std::mt19937 rng(69420);

int f(Mask mask)
{
    if (mask.perms.size() == 1)
    {
        return 0;
    }

    if (mem.count(mask))
    {
        return mem[mask];
    }

    std::set <Operation> used;
    std::vector <std::pair <std::vector <Mask>, Operation>> received;
    for (int t = 0 ; t < 3 ; ++t)
    {
        for (int i = 0 ; i < T_CONST ; ++i)
        {
            int a, b, c;
            do
            {
                a = rng()%N + 1;
                b = rng()%(N - 1) + 1;
                if (b >= a) b++;

                c = rng()%(N - 2) + 1;
                if (c >= std::min(a, b)) c++;
                if (c >= std::max(a, b)) c++;

            } while(used.count({t, a, b, c, 0}));

            used.insert({t, a, b, c, 0});
            Operation curr(t, a, b, c);
            received.push_back({mask.split(t, a, b, c), curr});

        };
    }

    for (int i = 0 ; i < T_CONST ; ++i)
    {
        int a, b, c, d;
        do
        {
            a = rng()%N + 1;
            b = rng()%(N - 1) + 1;
            if (b >= a) b++;

            c = rng()%(N - 2) + 1;
            if (c >= std::min(a, b)) c++;
            if (c >= std::max(a, b)) c++;
            
            d = rng()%N + 1;

        } while(d == a || d == b || d == c || used.count({3, a, b, c, d}));

        used.insert({3, a, b, c, d});
        Operation curr(3, a, b, c, d);
        received.push_back({mask.split(3, a, b, c, d), curr});
    };

    std::sort(received.begin(), received.end(), [&](auto x, auto y)
    {
        int szX = 0;
        int szY = 0;
        
        for (int i = 0 ; i < x.first.size() ; ++i)
        {
            szX = std::max(szX, (int)x.first[i].perms.size());
        }

        for (int i = 0 ; i < y.first.size() ; ++i)
        {
            szY = std::max(szY, (int)y.first[i].perms.size());
        }

        return szX < szY;
    });

    int res = 0;
    next[mask] = received[0].second;
    for (const auto &curr : received[0].first)
    {
        res = std::max(res, f(curr));
    }

    res++;
    return res;
}

int perm[N];
void init(int T) 
{
    Mask curr;
    std::iota(perm, perm + N, 1);
    do
    {
        Permutation currP(perm);
        curr.perms.push_back(currP);
    } while (std::next_permutation(perm, perm + N));
}

int w[N];
int wRes[N];
void orderCoins() 
{
    Mask curr;
    std::iota(perm, perm + N, 1);
    do
    {
        Permutation currP(perm);
        curr.perms.push_back(currP);
    } while (std::next_permutation(perm, perm + N));

    Permutation myPerm;
    myPerm.vals[0] = 3;
    myPerm.vals[1] = 2;
    myPerm.vals[2] = 5;
    myPerm.vals[3] = 1;
    myPerm.vals[4] = 4;
    myPerm.vals[5] = 6;

    while (curr.perms.size() > 1)
    {
        f(curr);
        int res;
        Operation op = next[curr];
        if (op.t == 0)
        {
            res = getLightest(op.a, op.b, op.c);
        } 

        if (op.t == 1)
        {
            res = getHeaviest(op.a, op.b, op.c);
        } 

        if (op.t == 2)
        {
            res = getMedian(op.a, op.b, op.c);
        } 

        if (op.t == 3)
        {
            res = getNextLightest(op.a, op.b, op.c, op.d);
        } 

        curr = curr.getSplit(res, op.t, op.a, op.b, op.c, op.d);
    }   

    assert(curr.perms.size() == 1);
    for (int i = 0 ; i < N ; ++i)
    {
        wRes[i] = curr.perms[0].vals[i];
    }

    for (int i = 0 ; i < N ; ++i)
    {
        w[wRes[i] - 1] = i + 1;
    }

    answer(w);
}

Compilation message (stderr)

scales.cpp: In member function 'std::vector<Mask> Mask::split(int, int, int, int, int)':
scales.cpp:134:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<Permutation>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  134 |         for (int i = 0 ; i < perms.size() ; ++i)
      |                          ~~^~~~~~~~~~~~~~
scales.cpp: In member function 'Mask Mask::getSplit(int, int, int, int, int, int)':
scales.cpp:159:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<Permutation>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  159 |         for (int i = 0 ; i < perms.size() ; ++i)
      |                          ~~^~~~~~~~~~~~~~
scales.cpp:170:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<Mask>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  170 |         for (int i = 0 ; i < res.size() ; ++i)
      |                          ~~^~~~~~~~~~~~
scales.cpp: In function 'bool operator<(const Mask&, const Mask&)':
scales.cpp:184:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<Permutation>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  184 |         for (int i = 0 ; i < a.perms.size() ; ++i)
      |                          ~~^~~~~~~~~~~~~~~~
scales.cpp: In function 'int f(Mask)':
scales.cpp:250:29: warning: conversion from 'std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>::result_type' {aka 'long unsigned int'} to 'int' may change value [-Wconversion]
  250 |                 a = rng()%N + 1;
      |                     ~~~~~~~~^~~
scales.cpp:251:35: warning: conversion from 'std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>::result_type' {aka 'long unsigned int'} to 'int' may change value [-Wconversion]
  251 |                 b = rng()%(N - 1) + 1;
      |                     ~~~~~~~~~~~~~~^~~
scales.cpp:272:25: warning: conversion from 'std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>::result_type' {aka 'long unsigned int'} to 'int' may change value [-Wconversion]
  272 |             a = rng()%N + 1;
      |                 ~~~~~~~~^~~
scales.cpp:273:31: warning: conversion from 'std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>::result_type' {aka 'long unsigned int'} to 'int' may change value [-Wconversion]
  273 |             b = rng()%(N - 1) + 1;
      |                 ~~~~~~~~~~~~~~^~~
scales.cpp:280:25: warning: conversion from 'std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>::result_type' {aka 'long unsigned int'} to 'int' may change value [-Wconversion]
  280 |             d = rng()%N + 1;
      |                 ~~~~~~~~^~~
scales.cpp: In function 'void init(int)':
scales.cpp:319:15: warning: unused parameter 'T' [-Wunused-parameter]
  319 | void init(int T)
      |           ~~~~^
scales.cpp: In instantiation of 'f(Mask)::<lambda(auto:1, auto:2)> [with auto:1 = std::pair<std::vector<Mask>, Operation>; auto:2 = std::pair<std::vector<Mask>, Operation>]':
/usr/include/c++/10/bits/predefined_ops.h:156:30:   required from 'constexpr bool __gnu_cxx::__ops::_Iter_comp_iter<_Compare>::operator()(_Iterator1, _Iterator2) [with _Iterator1 = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Iterator2 = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Compare = f(Mask)::<lambda(auto:1, auto:2)>]'
/usr/include/c++/10/bits/stl_algo.h:82:17:   required from 'void std::__move_median_to_first(_Iterator, _Iterator, _Iterator, _Iterator, _Compare) [with _Iterator = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<f(Mask)::<lambda(auto:1, auto:2)> >]'
/usr/include/c++/10/bits/stl_algo.h:1924:34:   required from '_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<f(Mask)::<lambda(auto:1, auto:2)> >]'
/usr/include/c++/10/bits/stl_algo.h:1958:38:   required from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Size = long int; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<f(Mask)::<lambda(auto:1, auto:2)> >]'
/usr/include/c++/10/bits/stl_algo.h:1974:25:   required from 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<f(Mask)::<lambda(auto:1, auto:2)> >]'
/usr/include/c++/10/bits/stl_algo.h:4892:18:   required from 'void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<std::pair<std::vector<Mask>, Operation>*, std::vector<std::pair<std::vector<Mask>, Operation> > >; _Compare = f(Mask)::<lambda(auto:1, auto:2)>]'
scales.cpp:305:6:   required from here
scales.cpp:294:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<Mask>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  294 |         for (int i = 0 ; i < x.first.size() ; ++i)
      |                          ~~^~~~~~~~~~~~~~~~
scales.cpp:299:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<Mask>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  299 |         for (int i = 0 ; i < y.first.size() ; ++i)
      |                          ~~^~~~~~~~~~~~~~~~
scales.cpp: In member function 'int Permutation::getRes(int, int, int, int, int)':
scales.cpp:93:5: warning: control reaches end of non-void function [-Wreturn-type]
   93 |     }
      |     ^
scales.cpp: In member function 'int Permutation::getLightest(int, int, int)':
scales.cpp:40:5: warning: control reaches end of non-void function [-Wreturn-type]
   40 |     }
      |     ^
scales.cpp: In member function 'int Permutation::getHeaviest(int, int, int)':
scales.cpp:48:5: warning: control reaches end of non-void function [-Wreturn-type]
   48 |     }
      |     ^
scales.cpp: In member function 'int Permutation::getMedian(int, int, int)':
scales.cpp:57:5: warning: control reaches end of non-void function [-Wreturn-type]
   57 |     }
      |     ^
scales.cpp: In member function 'int Permutation::getNextLightest(int, int, int, int)':
scales.cpp:66:27: warning: control reaches end of non-void function [-Wreturn-type]
   66 |         std::vector <int> coins;
      |                           ^~~~~
scales.cpp: In member function 'int Permutation::getLightest(int, int)':
scales.cpp:32:5: warning: control reaches end of non-void function [-Wreturn-type]
   32 |     }
      |     ^
scales.cpp: In member function 'Mask Mask::getSplit(int, int, int, int, int, int)':
scales.cpp:150:28: warning: control reaches end of non-void function [-Wreturn-type]
  150 |         std::vector <Mask> res;
      |                            ^~~
scales.cpp: In function 'void orderCoins()':
scales.cpp:375:63: warning: 'res' may be used uninitialized in this function [-Wmaybe-uninitialized]
  375 |         curr = curr.getSplit(res, op.t, op.a, op.b, op.c, op.d);
      |                                                               ^
#Verdict Execution timeMemoryGrader output
Fetching results...