#include "controller_lib.h"
#include <bits/stdc++.h>
using namespace std;


#define CHECK(x) if(!(x)) { perror(#x); exit(1); }

string judge_message_str;
void judge_message(string msg) {
  if(!judge_message_str.empty()) judge_message_str += "; ";
  judge_message_str += msg;
}
[[noreturn]] void wrong_answer(string msg) {
  judge_message(msg);
  //grade(0, "translate:wrong", judge_message_str.c_str());
  grade(0, "Output isn't correct", judge_message_str.c_str());
}
[[noreturn]] void accept_with_score(float score) {
  //grade(score, (score == 1.0f ? "translate:success" : "translate:partial"), judge_message_str.c_str());
  grade(score, (score == 1.0f ? "Output is correct" : "Output is partially correct"), judge_message_str.c_str());
}
[[noreturn]] void judge_error(string msg) {
  judge_message(msg);
  fprintf(stderr, "ADMIN_MESSAGE: %s\n", judge_message_str.c_str());
  exit(1);
}

const int64_t MAX_POS = 1e18;
const int MAX_ROUNDS = 500;
int max_write_bound = 0;

struct Process {
  FILE *from_contestant = nullptr, *to_contestant = nullptr;
  int uid = 0;
  void setup_pipes(FILE* to, FILE* from) {
    to_contestant = to;
    from_contestant = from;
  }
  void write(string line) {
    int rc = fputs((line+"\n").c_str(), to_contestant);
    if(rc == EOF)
      wrong_answer("failed to write, exited too early?");
    rc = fflush(to_contestant);
    if(rc != 0)
      wrong_answer("broken pipe, exited too early?");
  }
  struct Query {
    enum { UNKNOWN, READ, WRITE, ANSWER } type = UNKNOWN;
    int64_t N = 0;
    int64_t P = 0;
    int64_t V = 0;
  };
  Query read() {
    Query q;
    int cmd = EOF;
    long long a = -1, b = -1;
    int r = -1;

    do {
      cmd = fgetc(from_contestant);
      if (cmd == EOF) wrong_answer("unexpected eof");
    } while (isspace(cmd));


    if (cmd == '!') {
      r = fscanf(from_contestant, " %lld", &a);
      if (r != 1) wrong_answer("failed to parse ! int");
      if (a < 0) wrong_answer("a < 0 in answer");
      q.type = Query::ANSWER;
      q.N = a;
      return q;
    }
    else if (cmd == 'w') {
      r = fscanf(from_contestant, " %lld %lld", &a, &b);
      if (r != 2) wrong_answer("failed to parse w int int");
      if(a < 0) wrong_answer("a < 0 in write");

      q.type = Query::WRITE;
      q.P = a;
      q.V = b;
      return q;
    }
    else if (cmd == 'r') {
      r = fscanf(from_contestant, " %lld", &a);
      if (r != 1) wrong_answer("failed to parse r int");
      if(a < 0) wrong_answer("a < 0 in read");

      q.type = Query::READ;
      q.P = a;
      return q;
    }

    wrong_answer(string("unexpected command ") + char(cmd));
  }
};

struct Testcase {
  int n, m;
  vector<unique_ptr<Process>> proc;
  map<int64_t,int> locations;
  int remain;
  int id = 0;
};

vector<Testcase> tests;
int handler(FILE **to_solution, FILE **from_solution, int num_proc) {
  int pr = 0;
  int max_n = 0;
  for(auto &t : tests) {
    max_n = max(max_n, t.n);
    for(int i = 0; i < t.n; ++i) {
      t.proc[i]->setup_pipes(to_solution[pr], from_solution[pr]);
      ++pr;
      string s = to_string(t.proc[i]->uid) + " " + to_string(t.m);
      t.proc[i]->write(s);
    }
  }

  auto any_ongoing = [&](){
    for(auto &t : tests)
      if(t.remain) return true;
    return false;
  };

  const bool WRITES_ACROSS_TESTS = (max_n > 2);

  int rounds = 0;
  int max_write = 0;
  while(any_ongoing()) {
    rounds++;
    if(rounds > MAX_ROUNDS) wrong_answer("too many rounds");
    map<int64_t,int> writes_any_test_case_to_id;

    for(auto &t : tests) if(t.remain) {
      map<int64_t,int> writes;
      for(unsigned i = 0; i < t.proc.size(); ++i) if(t.proc[i]) {
        auto q = t.proc[i]->read();
        if(q.type == Process::Query::ANSWER) {
          if(q.N != t.n)
            wrong_answer("guess " + to_string(q.N) + "; expected" + to_string(t.n));
          t.proc[i].reset();
          --t.remain;
        }
        else {
          if(q.P < 0 || q.P >= MAX_POS)
            wrong_answer("read outside of array");

          if(q.type == Process::Query::READ) {
            t.proc[i]->write(to_string(t.locations[q.P]));
          }
          else if(q.type == Process::Query::WRITE) {
            if(q.V < 0 || q.V > int(1e9))
              wrong_answer("write outside range");
            if(writes.count(q.P))
              wrong_answer("double write");
            writes[q.P] = q.V;
            if(rounds <= 2) {
              // in first two rounds any write can only safely be based on ID,
              // so we can guard against double writes across testcases.
              // Enabled except for n=2 subtask, where hashing intuitively
              // should wor
              if(WRITES_ACROSS_TESTS && writes_any_test_case_to_id.count(q.P)
                 && writes_any_test_case_to_id[q.P] != t.proc[i]->uid)
                wrong_answer("potential double write");
              writes_any_test_case_to_id[q.P] = t.proc[i]->uid;
            }
            max_write = max<int>(q.V, max_write);
          }
          else judge_error("bad query type; impossible?");
        }
      }
      for(auto [a,b] : writes) t.locations[a] = b;
    }
  }

  judge_message("rounds: " + to_string(rounds));

  if(max_write > max_write_bound)
    wrong_answer("max_write="+to_string(max_write));

  //float score = (0.2 + 0.8 * exp((65.0-rounds)/100.0));
  float score = (0.2 + 0.8 * pow(1.01, 60.0-rounds));
  if(score > 1.0) score = 1.0;
  if(score < 0.0) score = 0.0;
  accept_with_score(score);

  return 0;
}

int main(int argv, char** argc) {
  ifstream tin("input.txt");

  int m, number_tests;
  tin >> m >> max_write_bound;
  tin >> number_tests;

  int pr = 0;
  tests.resize(number_tests);
  int tcs = 0;
  for(auto &t : tests) {
    tin >> t.n;
    t.m = m;
    t.id = ++tcs;
    t.remain = t.n;
    t.proc.resize(t.n);
    for(int i = 0; i < t.n; ++i) {
      int uid;
      tin>>uid;
      t.proc[i] = make_unique<Process>();
      t.proc[i]->uid = uid;
      ++pr;
    }
  }

  return start_many_solutions(handler, pr);
}
