結果

問題 No.2958 Placing Many L-s
コンテスト
ユーザー simasima_71
提出日時 2026-09-19 01:29:26
言語 C++23(gcc16)
(gcc 16.1.0 + boost 1.92.0 + ACL)
コンパイル:
g++-16 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 111 ms / 2,000 ms
+ 450µs
コード長 5,862 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 6,466 ms
コンパイル使用メモリ 406,860 KB
実行使用メモリ 6,528 KB
最終ジャッジ日時 2026-09-19 01:29:36
合計ジャッジ時間 8,259 ms
ジャッジサーバーID
(参考情報)
judge2_1 / judge3_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 29
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using namespace atcoder;
#define rep(i, l, r) for (ll i = (l); i < (r); ++i)
#define all(x) (x).begin(), (x).end()
using ll = long long;
using pl = pair<ll,ll>;
using vl = vector<ll>;
using vvl = vector<vector<ll>>;
using vvvl = vector<vector<vector<ll>>>;
using vvvvl = vector<vector<vector<vector<ll>>>>;
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <regex>
using mint=modint998244353;

//グリッド構築24題対策ライブラリ

using Board = std::vector<std::vector<int>>;

// Rotations allowed; reflections forbidden. n,m must be positive.
// Returns nullopt exactly when no tiling exists.
// Time O(n*m), space O(n*m), including the returned board.
inline std::optional<Board> tileTetromino(int n, int m, char type) {
    if (n <= 0 || m <= 0)
        throw std::invalid_argument("n and m must be positive");
    if (std::string("STZIOLJ").find(type) == std::string::npos)
        throw std::invalid_argument("Unknown tetromino type");

    const long long area = 1LL * n * m;
    bool possible = false;
    switch (type) {
        case 'I': possible = n % 4 == 0 || m % 4 == 0; break;
        case 'O': possible = n % 2 == 0 && m % 2 == 0; break;
        case 'T': possible = n % 4 == 0 && m % 4 == 0; break;
        case 'L': case 'J':
            possible = area % 8 == 0 && n != 1 && n != 3
                                      && m != 1 && m != 3;
            break;
        case 'S': case 'Z': break;
    }
    if (!possible) return std::nullopt;
    if (area / 4 > std::numeric_limits<int>::max())
        throw std::length_error("Tile IDs do not fit in int");

    int h = n, w = m;
    bool rotate = false;
    if (type == 'L' || type == 'J') {
        // Even case: w is divisible by 4.
        // Odd case: h is odd, w is divisible by 8.
        if ((h % 2 == 0 && w % 2 == 0 && w % 4 != 0) ||
            (h % 2 == 0 && w % 2 != 0)) {
            std::swap(h, w);
            rotate = true;
        }
    }

    Board ans(n, std::vector<int>(m));
    int offset = 0;
    auto put = [&](int r, int c, const Board& p, int count) {
        for (int i = 0; i < static_cast<int>(p.size()); ++i) {
            for (int j = 0; j < static_cast<int>(p[i].size()); ++j) {
                // Rotate the entire virtual board by 90 degrees if needed.
                int rr = rotate ? c + j : r + i;
                int cc = rotate ? m - 1 - (r + i) : c + j;
                // Reflect an all-L tiling to obtain an all-J tiling.
                if (type == 'J') cc = m - 1 - cc;
                ans[rr][cc] = offset + p[i][j];
            }
        }
        offset += count;
    };

    if (type == 'I' || type == 'O' || type == 'T') {
        Board p;
        int count;
        if (type == 'I') {
            p = (m % 4 == 0) ? Board{{1, 1, 1, 1}}
                             : Board{{1}, {1}, {1}, {1}};
            count = 1;
        } else if (type == 'O') {
            p = {{1, 1}, {1, 1}};
            count = 1;
        } else {
            p = {{1, 1, 1, 2},
                 {3, 1, 2, 2},
                 {3, 3, 4, 2},
                 {3, 4, 4, 4}};
            count = 4;
        }
        int ph = static_cast<int>(p.size());
        int pw = static_cast<int>(p[0].size());
        for (int r = 0; r < h; r += ph)
            for (int c = 0; c < w; c += pw)
                put(r, c, p, count);
    } else {
        const Board p2 = {{1, 1, 1, 2},
                          {1, 2, 2, 2}};
        const Board p5 = {{1, 1, 1, 5, 6, 2, 2, 2},
                          {1, 5, 5, 5, 6, 2, 3, 3},
                          {10, 9, 9, 9, 6, 6, 4, 3},
                          {10, 9, 8, 8, 8, 7, 4, 3},
                          {10, 10, 8, 7, 7, 7, 4, 4}};
        int start = 0;
        if (h % 2 != 0) {
            for (int c = 0; c < w; c += 8)
                put(0, c, p5, 10);
            start = 5;
        }
        for (int r = start; r < h; r += 2)
            for (int c = 0; c < w; c += 4)
                put(r, c, p2, 2);
    }
    return ans;
}

// 回転・裏返しを許可する版。
// 前の tileTetromino が定義されていることが必要。
// 時間・空間計算量:O(n*m)
inline std::optional<Board> tileTetrominoWithReflection(
    int n, int m, char type
) {
    // L・J以外、または辺の長さに3がない場合は前の関数でよい。
    if ((type != 'L' && type != 'J') || (n != 3 && m != 3)) {
        return tileTetromino(n, m, type);
    }

    if (n <= 0 || m <= 0) {
        throw std::invalid_argument("n and m must be positive");
    }

    // 3 × length の長方形として構成する。
    const int length = (n == 3 ? m : n);
    if (length % 8 != 0) {
        return std::nullopt;
    }

    const int pattern[3][8] = {
        {1, 1, 2, 2, 2, 3, 4, 4},
        {1, 5, 2, 3, 3, 3, 6, 4},
        {1, 5, 5, 5, 6, 6, 6, 4}
    };

    Board ans(n, std::vector<int>(m));
    int offset = 0;

    for (int start = 0; start < length; start += 8) {
        for (int r = 0; r < 3; ++r) {
            for (int c = 0; c < 8; ++c) {
                int id = offset + pattern[r][c];

                if (n == 3) {
                    ans[r][start + c] = id;
                } else {
                    ans[start + c][r] = id;
                }
            }
        }
        offset += 6;
    }

    return ans;
}

int main(){
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    ll tt;
    cin>>tt;
    rep(iaa,0,tt){
    ll n,m;
    cin>>n>>m;
    auto u=tileTetrominoWithReflection(n,m,'L');
    if(!u){
        cout<<-1<<endl;
        continue;
    }
    const auto& board = *u;
    cout<<n*m/4<<endl;
    rep(i,0,board.size()){
        rep(j,0,board[i].size()){
            cout<<board[i][j]<<" ";
        }
        cout<<endl;
    }
}
}
0