제출 #1343914

#제출 시각아이디문제언어결과실행 시간메모리
1343914poatMake them Meet (EGOI24_makethemmeet)C++17
100 / 100
8 ms848 KiB
#include <bits/stdc++.h>
using namespace std;
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef long double ld;

const int MAXN = 201;
int n,m;
vector<vi> C(MAXN, vi());
int ADJ[MAXN][MAXN] = {0};
vector<vi> ANS;

int root, n1, n2; // root and its neighbours

int PAR[MAXN] = {0};
int DEPTH[MAXN] = {0};
int MAX_SUBTREE_DEPTH[MAXN] = {0};
int mark[MAXN] = {0};
vector<vi> TREE(MAXN, vi());

void dfs1(int i, int par){
    if(mark[i] == 1)return;
    mark[i] = 1;
    PAR[i] = par;
    if(par != -1)DEPTH[i] = DEPTH[par]+1;
    MAX_SUBTREE_DEPTH[i] = DEPTH[i];
    trav(y, C[i]){
        if(mark[y] == 0){
            TREE[i].push_back(y);
            dfs1(y, i);
            MAX_SUBTREE_DEPTH[i] = max(MAX_SUBTREE_DEPTH[i], MAX_SUBTREE_DEPTH[y]);
        }
    }
}

int F[MAXN] = {0};
int B[MAXN] = {0};
int f = 0; // number of f:s

void make_move(vi col){

    vi new_f(n,0);
    ANS.push_back(col);

    rep(c1,0,n){
        bool OR = 0;
        bool alone = 1;
        trav(y, C[c1]){
            if(col[y] == col[c1]){
                alone = 0;
                OR |= F[y];
            }
        }

        if(alone){
            new_f[c1] = F[c1];
        }
        else{
            new_f[c1] = OR;
        }
    }

    f = 0;
    rep(c1,0,n){
        F[c1] = new_f[c1];
        f += F[c1];
    }
}

void move_group(vi v){
    // color v the same, color everything else in different colors
    vi in_group(n,0);
    vi col(n,0);
    trav(y, v){
        in_group[y] = 1;
    }
    int c = 2;
    rep(c1,0,n){
        if(in_group[c1]){
            col[c1] = 1;
        }
        else{
            col[c1] = c;
            c++;
        }
    }
    make_move(col);
}

int max_depth = 0;

bool comp_tree(int i, int j){
    return MAX_SUBTREE_DEPTH[i] < MAX_SUBTREE_DEPTH[j];
}

bool last_visited[MAXN] = {0};
int last_seen = 0;

void last_dfs(int i){
    if(!last_visited[i]){
        last_visited[i] = 1;
        last_seen++;
    }
    if(last_seen == n)return;
    sort(all(TREE[i]), comp_tree);
    trav(y, TREE[i]){
        move_group({i, y});
        last_dfs(y);
        if(last_seen == n)return;
        move_group({i, y});
    }
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    
    cin >> n >> m;

    if(m == (n*n-n)/2){
        // Clique
        // Greedy matching seems to be linear
        // Can also be done with divide and conquer
        vector<vi> done(n, vi(n, 0));
        int matched = 0;
        while(matched < (n*n-n)/2){
            vi row(n,-1);
            int color = 1;
            rep(c1,0,n){
                if(row[c1] == -1){
                    row[c1] = color;
                    rep(c2,1,n){
                        int j = (c1+c2)%n;
                        if(row[j] == -1 && done[c1][j] == 0){
                            done[c1][j] = 1;
                            done[j][c1] = 1;
                            matched++;
                            row[j] = color;
                            break;
                        }
                    }
                    color++;
                }
            }
            ANS.push_back(row);
            ANS.push_back(row);
        }
    }
    else{
        // Non-clique
        rep(c1,0,m){
            int a,b;
            cin >> a >> b;
            C[a].push_back(b);
            C[b].push_back(a);
            ADJ[a][b] = 1;
            ADJ[b][a] = 1;
        }

        // Find root. n^3 because why not.
        rep(c1,0,n){
            rep(c2,0,n){
                rep(c3,0,n){
                    if(c1 != c2 && c1 != c3 && c2 != c3){
                        if(ADJ[c2][c1] && ADJ[c1][c3] && !ADJ[c2][c3]){
                            root = c1;
                            n1 = c2;
                            n2 = c3;
                            goto root_done;
                        }
                    }
                }
            }
        }

        root_done:

        swap(n1, root); // better if n1 is the root

        dfs1(root, -1);

        rep(c1,0,n){
            max_depth = max(max_depth, DEPTH[c1]);
            if(c1 != root)F[c1] = 1;
            int min_depth = n+1;
            trav(y, C[c1]){
                if(DEPTH[y] < min_depth){
                    min_depth = DEPTH[y];
                    B[c1] = y;
                }
            }
        }
        f = n-1;

        // make F[x] = 0 where for max_depth-1
        rep(d,0,max_depth-1){
            vi v;
            rep(c1,0,n){
                if(DEPTH[c1] == d || DEPTH[c1] == d+1){
                    v.push_back(c1);
                }
            }
            move_group(v);
        }

        for(int d = max_depth-1; d >= 1; d--){
            rep(c1,0,n){
                if(DEPTH[B[c1]] == d){
                    move_group({c1, B[c1], PAR[B[c1]]});
                    move_group({B[c1], PAR[B[c1]]});
                }
            }

            vi v;
            rep(c1,0,n){
                if(DEPTH[c1] == d || DEPTH[c1] == d-1){
                    v.push_back(c1);
                }
            }
            move_group(v);
        }

        // remove any extra F from n1
        move_group({root, n1});
        move_group({root, n1, n2});
        move_group({n1, n2});

        rep(c1,0,n){
            if(F[c1] == 1 && c1 != n2){
                // This should be a neighbour of the root
                move_group({c1, root});
                move_group({root, n1, n2});
                move_group({n1, n2});
            }
        }

        // this is a bit unnecessary, but only 2 queries so who cares
        move_group({n1, n2});
        move_group({n1, root});

        // everyone now at root

        assert(f == 1);

        last_dfs(root);

    }

    cout << sz(ANS) << "\n";
    trav(v, ANS){
        trav(c, v){
            cout << c << " ";
        }cout << "\n";
    }
	
 
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...