#include #include #include #include using namespace std; #define MIN(A,B) ((A)<(B)?(A):(B)) #define MAX(A,B) ((A)>(B)?(A):(B)) #define ABS(A) ((A)>=(0.0)?(A):(-(A))) //#define DOTEST //#define DODEBUG //#define CHECKVALIDCASE #ifdef DODEBUG #define DEBUG(X) cerr << X; #else #define DEBUG(X) #endif double EPS = 1E-6; // BRUTE FORCE bool wins(double X, vector F) { // assuming Mikael made last move if (X <= 1.0) { return false; } for (size_t kn = 0; kn < F.size(); kn++) { if (X * F[kn] <= 1.0) { return true; } } for (size_t kn = 0; kn < F.size(); kn++) { bool w = true; for (size_t km = 0; km < F.size(); km++) { if (!wins(X * F[kn] * F[km], F)) { w = false; break; } } if (w) { return true; } } return false; } void brute(double X, vector F) { if (wins(X, F)) { cout << "Nils" << endl; } else { cout << "Mikael" << endl; } } // FANCY PANTS MOUSTACHE (not optimal) class IntervalSet { public: friend ostream& operator<<(ostream& os, IntervalSet is); typedef map map_t; typedef pair pair_t; typedef map_t::iterator iter_t; map_t values; double maxvalue; IntervalSet() { maxvalue = 1e30; } IntervalSet(double _maxvalue) { maxvalue = _maxvalue; } void addi(double start, double end) { if (start < maxvalue) { values.insert(pair_t(start, MIN(end, maxvalue))); } } void addinter(double start, double end) { if (values.size() > 0) { iter_t it = values.upper_bound(start); // starts before if (it != values.begin()) { it--; if (start < it->second) { start = it->first; end = MAX(end, it->second); values.erase(it); } } // starts inside while (true) { it = values.upper_bound(start); if (it == values.end() || end < it->first) { break; } end = MAX(end, it->second); values.erase(it); } } addi(start, end); } bool containspoint(double point) { if (empty()) { return false; } iter_t it = values.upper_bound(point); if (it == values.begin()) { return false; } it--; if (point < it->second) { return true; } else { return false; } } bool empty() { return values.size() == 0; } bool equals(IntervalSet& other) { iter_t it = values.begin(); iter_t ot = other.values.begin(); while (true) { if (it == values.end() || ot == other.values.end()) { if (it == values.end() && ot == other.values.end()) { return true; } else { return false; } } if (it->first != ot->first || it->second != ot->second) { return false; } it++; ot++; } } IntervalSet intersect(IntervalSet& other) { DEBUG("intersect between " << *this << "\n" << " and " << other << "\n"); IntervalSet result(MIN(maxvalue, other.maxvalue)); iter_t sit = values.begin(); iter_t oit = other.values.begin(); while (sit != values.end() && oit != other.values.end()) { iter_t it1, it2; if (sit->first < oit->first) { it1 = sit; it2 = oit; //sit++; } else { it1 = oit; it2 = sit; //oit++; } if (sit->second < oit->second) { sit++; } else { oit++; } if (it2->first < it1->second) { result.values.insert( pair_t(it2->first, MIN(it1->second, it2->second))); } } DEBUG(" gives " << result << endl); #ifdef DOTEST for (double x = 0.0; x < result.maxvalue; x += 0.1) { if (containspoint(x) && other.containspoint(x) && !result.containspoint(x)) { cerr << "BROKEN INTERSECT " << x << endl; exit(0); } } #endif return result; } IntervalSet mult(double factor) { IntervalSet res(maxvalue); for (iter_t it = values.begin(); it != values.end(); it++) { res.values[it->first * factor] = it->second * factor; } return res; } IntervalSet unionn(IntervalSet& other) { IntervalSet result = *this; DEBUG("union between " << *this << "\n" << " and " << other << "\n"); for (iter_t ot = other.values.begin(); ot != other.values.end(); ot++) { result.addinter(ot->first, ot->second); } DEBUG(" gives " << result << endl); #ifdef DOTEST for (double x = 0.0; x < result.maxvalue; x += 0.1) { if ((containspoint(x) || other.containspoint(x)) && !result.containspoint(x)) { cerr << "BROKEN UNION " << x << endl; exit(0); } } #endif return result; } }; ostream& operator<<(ostream& os, IntervalSet is) { os << "{ "; for (map::const_iterator it = is.values.begin(); it != is.values.end(); it++) { os.precision(4); os << it->first << "," << it->second << " "; } os << "}"; return os; } #ifdef DOTEST void check(double X, vector F, size_t kn, IntervalSet& orig, IntervalSet& resu) { size_t K = F.size(); // check that all are found that should have been for (double x = 1.1; x < X; x += 0.1) { if (resu.containspoint(x) && ! wins(x, F)) { cerr << "\nILLEGAL GOOD: " << x << " (" << wins(x,F) << ")" << endl; exit(1); } bool good = true; for (size_t km = 0; km < K; km++) { double v = x * F[kn] * F[km]; if (! orig.containspoint(v)) { good = false; break; } } if (good && !resu.containspoint(x)) { cerr << "\nMISSING GOOD: " << x << endl; for (size_t km = 0; km < K; km++) { double v = x * F[kn] * F[km]; cerr << " x * F[kn] * F[km] = " << x << " * " << F[kn] << " * " << F[km] << " = " << v << " exists: " << orig.containspoint(v) << endl; } exit(1); } } DEBUG("ALL OK\n"); } #endif void solve(double X, vector F) { IntervalSet good(X + 1.0); good.addinter(1.0, 1.0/F[0]); size_t K = F.size(); bool change = true; while (change) { change = false; DEBUG("\nGOT START " << good << endl); for (size_t kn = 0; kn < K; kn++) { DEBUG("Trying weapon " << F[kn] << " "); IntervalSet play = good.mult(1.0 / F[kn]); DEBUG(play << endl); IntervalSet counter[6]; for (size_t km = 0; km < K; km++) { DEBUG(" against counter " << F[km] << " "); counter[km] = play.mult(1.0 / F[km]); DEBUG(counter[km] << endl); } IntervalSet result = counter[0]; for (size_t km = 1; km < K; km++) { result = result.intersect(counter[km]); } result = good.unionn(result); #ifdef DOTEST check(X, F, kn, good, result); #endif if (!result.equals(good)) { DEBUG("old good " << good << endl); change |= true; good = result; DEBUG("new good " << good << endl); } } } DEBUG("\nFINAL INTERVALS " << good << endl); #ifdef DOTEST for (double x = 0.0; x < X; x += 0.1) { if (wins(x,F) && !good.containspoint(x)) { cerr << "MISSING WIN " << x << endl; exit(1); } if (!wins(x,F) && good.containspoint(x)) { cerr << "FALSE WIN " << x << endl; exit(1); } } #endif #ifdef CHECKVALIDCASE for (IntervalSet::iter_t it = good.values.begin(); it != good.values.end(); it++) { if (ABS(it->first - X) < EPS || ABS(it->second - X) < EPS) { cerr << "X=" << X << " is on the border of " << it->first << "," << it->second << endl; cerr << ABS(it->first - X) << " " << EPS << " " << ABS(it->second - X) << endl; exit(1); } } #endif if (good.containspoint(X)) { cout << "Nils" << endl; } else { cout << "Mikael" << endl; } } int main() { int N; cin >> N; for (int i = 0; i < N; i++) { double X; int K; cin >> X >> K; vector F(K); for (int k = 0; k < K; k++) { cin >> F[k]; } sort(F.begin(), F.end()); //brute(X, F); solve(X, F); } }