Problem: icpc2025_cerc_a
Difficulty: hard
Categories: data structures
Time limit: 1000 ms, memory limit: 256 MB

This task is interactive. After printing each line, you should flush the output buffer. You can use cout << flush in $\mathrm { C } + +$ , System.out.flush() in Java, and sys.stdout.flush() in Python. You must strictly follow the instructions in the Interaction section; otherwise you may receive verdicts like wrong answer, time limit exceeded, or others.

Because work in the mine is hard and time-consuming, the dwarves decided to seek help in automating some of their tasks. Their current task is to classify $N$ minerals (identified by numbers from 1 to $N$ ) into different classes. To assist with this, Dwarf the Worker has installed a new conveyor belt. The dwarves can add samples of minerals to the beginning of the belt and remove them from its end (i.e., remove the minerals that were added earliest).

Unfortunately, this conveyor belt has no knowledge base, so it cannot identify the class of any mineral on it. However, it has another useful feature: it displays how many distinct classes of minerals are currently on the belt. It turns out this is sufficient for the mine, as the dwarves do not need to know the class of each mineral: they just need to segregate the minerals into piles of the same class.

Can you help the dwarves solve this task using the conveyor belt?

# Interaction Protocol

The classes of minerals are fixed at the beginning and do not depend on the queries made.

First, read a line containing one integer $N$ , the number of minerals to classify. Then, you can perform operations of the following two types:

• + id — mineral with identifier $i d$ is added to the beginning of the conveyor belt, • - — the mineral at the end of the conveyor belt is removed. If the belt is empty, nothing happens.

After each operation, the conveyor belt outputs one line containing the number of distinct classes currently on it.

To output the answer, first print a line containing ! followed by $k$ being the number of distinct classes in the mine. Then print $k$ lines, each describing one class. Each line should contain a number $c _ { i }$ followed by $c _ { i }$ mineral identifiers of that class. Each of $N$ minerals must appear in exactly one class. You may output the classes and minerals within each class in any order.

Remember to flush the output after each operation and after writing the answer. Remember to put spaces between numbers and the $^ +$ , -, ! symbols. You must read all data from the interactor.

# Limits

$1 \le N \le 5 0 0$ , you can perform at most 35 000 operations.

# Sample interaction

The first sample test has $N = 3$ and the classes of minerals $1 , 2 , 3$ are $1 , 2 , 1$ respectively:

<table><tr><td>Input</td><td>Output</td><td>Status of the conveyor belt</td></tr><tr><td>3</td><td>+1</td><td>[1]</td></tr><tr><td>1</td><td>+2</td><td>[1，2]</td></tr><tr><td>2</td><td>+3</td><td>[1，2，1]</td></tr><tr><td>2</td><td>1</td><td>[2，1]</td></tr><tr><td rowspan="2">2</td><td>！2</td><td></td></tr><tr><td>213 12</td><td></td></tr></table>

# Local testing

In the Files section you can find A.zip containing sample tests and a grader grader.cpp. To test your solution, compile it, then pass the test name and your executable to the compiled ./grader:

./grader [test] [executable]

For example: ./grader 0b.in ./abc

The sample grader is not guaranteed to behave identically to the official one. However, neither is adaptive.

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;


static long long queries = 0;
static long long query_limit = 35000;

static const long long HARD_CAP = 350000;


static void log_metrics() {
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}


static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

int main(int argc, char** argv) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics);

    
    int n = inf.readInt();
    
    
    
    
    vector<int> mineral_class(n + 1);
    set<int> all_true_classes;
    for (int i = 1; i <= n; i++) {
        mineral_class[i] = inf.readInt();
        all_true_classes.insert(mineral_class[i]);
    }

    
    cout << n << endl;

    
    deque<int> belt;                
    map<int, int> class_counts;     
    int distinct_on_belt = 0;       

    while (true) {
        
        if (queries > HARD_CAP) {
            finish(_pe, "Hard query limit exceeded (spam protection)");
        }

        string token;
        
        if (!(cin >> token)) {
            finish(_pe, "Unexpected EOF: expected command or answer");
        }

        
        if (token == "?") {
            if (!(cin >> token)) {
                finish(_pe, "Unexpected EOF after '?'");
            }
        }

        if (token == "!") {
            
            int k;
            if (!(cin >> k)) {
                finish(_pe, "Expected integer k (number of classes) after '!'");
            }

            
            if (k != (int)all_true_classes.size()) {
                finish(_wa, format("Incorrect number of classes. Expected %d, found %d", 
                                   (int)all_true_classes.size(), k));
            }

            
            set<int> used_minerals;
            set<int> used_classes_output;
            
            for (int i = 0; i < k; i++) {
                int c_size;
                if (!(cin >> c_size)) finish(_pe, "Expected class size");
                if (c_size <= 0) finish(_wa, "Class size must be positive");

                int group_class = -1; 
                
                for (int j = 0; j < c_size; j++) {
                    int mid;
                    if (!(cin >> mid)) finish(_pe, "Expected mineral ID");
                    
                    if (mid < 1 || mid > n) {
                        finish(_wa, format("Mineral ID %d out of bounds [1, %d]", mid, n));
                    }
                    if (used_minerals.count(mid)) {
                        finish(_wa, format("Mineral %d appears in multiple classes", mid));
                    }
                    used_minerals.insert(mid);

                    int actual_class = mineral_class[mid];
                    if (group_class == -1) {
                        group_class = actual_class;
                    } else {
                        if (actual_class != group_class) {
                            finish(_wa, format("Mineral %d belongs to class %d, but previous minerals in this group belonged to class %d", 
                                               mid, actual_class, group_class));
                        }
                    }
                }

                
                if (used_classes_output.count(group_class)) {
                    finish(_wa, format("Class (internal ID %d) outputted as separate groups multiple times", group_class));
                }
                used_classes_output.insert(group_class);
            }

            
            if ((int)used_minerals.size() != n) {
                finish(_wa, format("Only %d out of %d minerals were classified", (int)used_minerals.size(), n));
            }

            finish(_ok, "Correct answer");
        } 
        else if (token == "+") {
            
            int id;
            if (!(cin >> id)) finish(_pe, "Expected mineral ID after '+'");
            
            if (id < 1 || id > n) {
                finish(_pe, format("Mineral ID %d out of bounds [1, %d]", id, n));
            }

            
            
            
            belt.push_back(id);
            int c = mineral_class[id];
            if (class_counts[c] == 0) {
                distinct_on_belt++;
            }
            class_counts[c]++;

            queries++;
            cout << distinct_on_belt << endl;
        } 
        else if (token == "-") {
            
            
            
            if (!belt.empty()) {
                int id = belt.front();
                belt.pop_front();
                int c = mineral_class[id];
                class_counts[c]--;
                if (class_counts[c] == 0) {
                    distinct_on_belt--;
                }
            }
            

            queries++;
            cout << distinct_on_belt << endl;
        } 
        else {
            finish(_pe, format("Invalid token '%s'", token.c_str()));
        }

        
        if (queries % 100 == 0) {
            log_metrics();
        }
    }

    return 0;
}


Adaptive interactor (C++):

Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);

    
    string mode = opt<string>("mode", "non");
    int n = opt<int>("n", -1);
    int k = opt<int>("k", -1);
    
    
    int seedVal = std::atoi(argv[1]);

    
    if (n == -1) {
        if (seedVal == 1) n = 1;
        else if (seedVal == 2) n = 2;
        else if (seedVal == 3) n = 3;
        else if (seedVal == 4) n = 500; 
        else if (seedVal == 5) n = 500;
        else if (seedVal == 6) n = 500;
        else {
            
            int type = rnd.next(1, 10);
            if (type <= 2) n = rnd.next(1, 50);       
            else if (type <= 4) n = rnd.next(50, 200); 
            else n = rnd.next(400, 500);               
        }
    }

    
    if (k == -1) {
        if (seedVal == 1) k = 1;
        else if (seedVal == 2) k = 1;       
        else if (seedVal == 3) k = 2;       
        else if (seedVal == 4) k = 1;       
        else if (seedVal == 5) k = n;       
        else if (seedVal == 6) k = 2;       
        else {
            int type = rnd.next(1, 10);
            if (type == 1) k = 1;
            else if (type == 2) k = n;
            else if (type <= 5) k = rnd.next(1, min(n, 10)); 
            else if (type <= 7) k = rnd.next(max(1, n / 2), n); 
            else k = rnd.next(1, n);
        }
    }

    
    if (k < 1) k = 1;
    if (k > n) k = n;

    if (mode == "adp") {
        
        
        cout << n << endl;
    } else {
        
        
        
        
        vector<int> counts = rnd.partition(k, n, 1);
        
        vector<int> classes;
        classes.reserve(n);
        
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < counts[i]; j++) {
                classes.push_back(i + 1); 
            }
        }
        
        
        shuffle(classes.begin(), classes.end());
        
        cout << n << endl;
        for (int i = 0; i < n; i++) {
            cout << classes[i] << (i == n - 1 ? "" : " ");
        }
        cout << endl;
    }

    return 0;
}