結果

問題 No.5022 XOR Printer
ユーザー mai
提出日時 2025-07-26 15:29:11
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 36 ms / 2,000 ms
コード長 18,037 bytes
コンパイル時間 4,548 ms
コンパイル使用メモリ 323,172 KB
実行使用メモリ 7,720 KB
スコア 4,914,685,184
最終ジャッジ日時 2025-07-26 15:29:20
合計ジャッジ時間 8,318 ms
ジャッジサーバーID
(参考情報)
judge2 / judge1
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます

ソースコード

diff #

#pragma GCC optimize("O3")
#include <bits/stdc++.h>

// clang-format off
using namespace std;
using ll = long long int;

#define all(v) (v).begin(),(v).end()
#define repeat(cnt,l) for(typename remove_const<typename remove_reference<decltype(l)>::type>::type cnt={};(cnt)<(l);++(cnt))
#define rrepeat(cnt,l) for(auto cnt=(l)-1;0<=(cnt);--(cnt))
#define iterate(cnt,b,e) for(auto cnt=(b);(cnt)!=(e);++(cnt))
#define upto(cnt,b,e,step) for(auto cnt=(b);(cnt)<=(e);(cnt)+=(step))
#define downto(cnt,b,e,step) for(auto cnt=(b);(e)<=(cnt);(cnt)-=(step))
const long long MD = 998244353; const long double PI = 3.1415926535897932384626433832795L;
template<typename T1, typename T2> inline ostream& operator <<(ostream &o, const pair<T1, T2> p) { o << '(' << p.first << ':' << p.second << ')'; return o; }
template<typename T> inline T& chmax(T& to, const T& val) { return to = max(to, val); }
template<typename T> inline T& chmin(T& to, const T& val) { return to = min(to, val); }
void bye(string s, int code = 0) { cout << s << endl; exit(code); }
mt19937_64 randdev(8901016);
template<typename T, typename Random = decltype(randdev), typename enable_if<is_integral<T>::value>::type* = nullptr>
inline T rand(T l, T h, Random& rand = randdev) { return uniform_int_distribution<T>(l, h)(rand); }
template<typename T, typename Random = decltype(randdev), typename enable_if<is_floating_point<T>::value>::type* = nullptr>
inline T rand(T l, T h, Random& rand = randdev) { return uniform_real_distribution<T>(l, h)(rand); }template<typename T>
static ostream& operator<<(ostream& o, const std::vector<T>& v) {
  o << "[ "; for(const auto& e : v) o<<e<<' '; return o << ']';
}

template <typename I> struct MyRangeFormat{ I b,e; MyRangeFormat(I _b, I _e):b(_b),e(_e){} };
template<typename I> static ostream& operator<<(ostream& o, const MyRangeFormat<I>& f) {
  o << "[ "; iterate(i,f.b,f.e) o<<*i<<' '; return o << ']';
}
template <typename I> struct MyMatrixFormat{
  const I& p; long long n, m;
  MyMatrixFormat(const I& _p, long long _n, long long _m):p(_p),n(_n),m(_m){}
};
template<typename I> static ostream& operator<<(ostream& o, const MyMatrixFormat<I>& f) {
  o<<'\n'; repeat(i,(f.n)) { repeat(j,f.m) o<<f.p[i][j]<<' '; o<<'\n'; }
  return o;
}
struct LOG_t { ~LOG_t() { clog << endl; } };
#define LOG (LOG_t(),clog<<'L'<<__LINE__<<": ")
#define FMTA(m,w) (MyRangeFormat<decltype(m+0)>(m,m+w))
#define FMTR(b,e) (MyRangeFormat<decltype(e)>(b,e))
#define FMTV(v) FMTR(v.begin(),v.end())
#define FMTM(m,h,w) (MyMatrixFormat<decltype(m+0)>(m,h,w))

#if defined(_WIN32) || defined(_WIN64)
#define getc_x _getc_nolock
#define putc_x _putc_nolock
#elif defined(__GNUC__)
#define getc_x getc_unlocked
#define putc_x putc_unlocked
#else
#define getc_x getc
#define putc_x putc
#endif
class MaiScanner {
  FILE* fp_;
  constexpr bool isvisiblechar(char c) noexcept { return (0x21<=(c)&&(c)<=0x7E); }
public:
  inline MaiScanner(FILE* fp):fp_(fp){}
  template<typename T> void input_integer(T& var) noexcept {
    var = 0; T sign = 1;
    int cc = getc_x(fp_);
    for (; cc < '0' || '9' < cc; cc = getc_x(fp_))
      if (cc == '-') sign = -1;
    for (; '0' <= cc && cc <= '9'; cc = getc_x(fp_))
      var = (var << 3) + (var << 1) + cc - '0';
    var = var * sign;
  }
  inline int c() noexcept { return getc_x(fp_); }
  template<typename T, typename enable_if<is_integral<T>::value, nullptr_t>::type = nullptr>
  inline MaiScanner& operator>>(T& var) noexcept { input_integer<T>(var); return *this; }
  inline MaiScanner& operator>>(string& var) {
    int cc = getc_x(fp_);
    for (; !isvisiblechar(cc); cc = getc_x(fp_));
    for (; isvisiblechar(cc); cc = getc_x(fp_))
      var.push_back(cc);
    return *this;
  }
  template<typename IT> inline void in(IT begin, IT end) { for (auto it = begin; it != end; ++it) *this >> *it; }
};
class MaiPrinter {
  FILE* fp_;
public:
  inline MaiPrinter(FILE* fp):fp_(fp){}
  template<typename T>
  void output_integer(T var) noexcept {
    if (var == 0) { putc_x('0', fp_); return; }
    if (var < 0)
      putc_x('-', fp_),
      var = -var;
    char stack[32]; int stack_p = 0;
    while (var)
      stack[stack_p++] = '0' + (var % 10),
      var /= 10;
    while (stack_p)
      putc_x(stack[--stack_p], fp_);
  }
  inline MaiPrinter& operator<<(char c) noexcept { putc_x(c, fp_); return *this; }
  template<typename T, typename enable_if<is_integral<T>::value, nullptr_t>::type = nullptr>
  inline MaiPrinter& operator<<(T var) noexcept { output_integer<T>(var); return *this; }
  inline MaiPrinter& operator<<(const char* str_p) noexcept { while (*str_p) putc_x(*(str_p++), fp_); return *this; }
  inline MaiPrinter& operator<<(const string& str) {
    const char* p = str.c_str();
    const char* l = p + str.size();
    while (p < l) putc_x(*p++, fp_);
    return *this;
  }
  template<typename IT> void join(IT begin, IT end, char sep = ' ') { for (bool b = 0; begin != end; ++begin, b = 1) b ? *this << sep << *begin : *this << *begin; }
};
MaiScanner scanner(stdin);
MaiPrinter printer(stdout);
// clang-format on

template <typename C = std::chrono::milliseconds> class Timer {
  std::chrono::system_clock::time_point tp_;

public:
  static inline auto now() { return std::chrono::system_clock::now(); }
  inline void tic() { tp_ = now(); }
  inline auto toc() const {
    return std::chrono::duration_cast<C>(now() - tp_).count();
  }
  inline Timer() : tp_(now()) {}
};
inline std::ostream &operator<<(std::ostream &o, const Timer<> &t) {
  return o << (long long)t.toc();
}

struct P {
  using T = int;
  T y, x;

  constexpr inline explicit P(T _y, T _x) : y(_y), x(_x) {}
  constexpr inline P() : y(0), x(0) {}

  constexpr inline bool operator==(P p) const { return y == p.y && x == p.x; }
  constexpr inline bool operator!=(P p) const { return y != p.y || x != p.x; }
  constexpr inline bool operator<(P p) const { return y == p.y ? x < p.x : y < p.y; }
  constexpr inline P operator+(P p) const { return P(y + p.y, x + p.x); }
  constexpr inline P operator-(P p) const { return P(y - p.y, x - p.x); }
  inline P &operator+=(P p) {
    y += p.y;
    x += p.x;
    return *this;
  }
  inline P &operator-=(P p) {
    y -= p.y;
    x -= p.x;
    return *this;
  }
  inline P &operator*=(T m) {
    y *= m;
    x *= m;
    return *this;
  }
  inline T distM(P p) const { return abs(y - p.y) + abs(x - p.x); }
  inline T distC(P p) const { return max(abs(y - p.y), abs(x - p.x)); }
  template <typename ITR> ITR nearestM(ITR begin, ITR end) const {
    if (begin == end)
      return end;
    T best = distM(*begin);
    ITR besti = begin;
    for (ITR it = begin; ++it, it != end;) {
      T m = distM(*it);
      if (best < m) {
        best = m;
        besti = it;
      }
    }
    return besti;
  }
};
inline ostream &operator<<(ostream &os, P p) {
  os << '(' << p.y << ',' << p.x << ')';
  return os;
}

const P FourMoving[] = {P(-1, 0), P(0, 1), P(1, 0), P(0, -1)};
const P FiveMoving[] = {P(-1, 0), P(0, 1), P(1, 0), P(0, -1), P(0, 0)};
const P EightMoving[] = {P(-1, 0),  P(0, 1),  P(1, 0),  P(0, -1),
                         P(-1, -1), P(-1, 1), P(1, -1), P(1, 1)};

inline P operator*(P::T m, P p) noexcept { return P(m * p.y, m * p.x); }

template <typename T>
// using T = int;
struct F {
  int height, width;
  vector<T> data;

  explicit F(int h, int w) : height(h), width(w), data(h * w) {}
  F() : F(1, 1) {}

  inline bool safe(int y, int x) const {
    return 0 <= y && y < height && 0 <= x && x < width;
  }
  inline bool safe(P p) const {
    return 0 <= p.y && p.y < height && 0 <= p.x && p.x < width;
  }

#if 1
  void assert_safe(int y, int x) const {
    if (!safe(y, x)) {
      clog << "assertion failed: field=" << height << "x" << width
           << ": try=" << y << "," << x << endl;
      assert(safe(y, x));
    }
  }
  inline T &operator()(int y, int x) {
    assert_safe(y, x);
    return data[x + y * width];
  }
  inline T &operator()(P p) {
    assert_safe(p.y, p. x);
    return data[p.x + p.y * width];
  }
  inline T operator()(int y, int x) const {
    assert_safe(y, x);
    return data[x + y * width];
  }
  inline T operator()(P p) const {
    assert_safe(p.y, p.x);
    return data[p.x + p.y * width];
  }
#else
  inline T &operator()(int y, int x) { return data[x + y * width]; }
  inline T &operator()(P p) { return data[p.x + p.y * width]; }
  inline T operator()(int y, int x) const { return data[x + y * width]; }
  inline T operator()(P p) const { return data[p.x + p.y * width]; }
#endif
  inline T getA(int i) const { return data[i]; }
  inline T &getAmut(int i) { return data[i]; }

  inline void fill(T e) { std::fill(data.begin(), data.end(), e); }
  inline void resize(int h, int w) {
    height = h;
    width = w;
    data.resize(h * w);
  }

  void print(ostream &os, int setw_arg = 4) {
    for (int y = 0; y < height; ++y) {
      for (int x = 0; x < width; ++x)
        os << setw(setw_arg) << operator()(y, x) << ' ';
      os << '\n';
    }
  }
};


class CommandLine {
  map<string, string> params;

  void initializeInternal(int argc, char **argv) {
    for (int i = 1; i < argc; ++i) {
      if (argv[i][0] == '-') { // TODO: `=` 区切りにしたい
        if (i + 1 < argc) {
          params.emplace(argv[i], argv[i + 1]);
          i += 1;
        }
      }
    }
  }

  CommandLine() = default;

public:
  static CommandLine &get() {
    static CommandLine g;
    return g;
  }
  static void initialize(int argc, char **argv) {
    get().initializeInternal(argc, argv);
  }
  const string &str(const string &key) {
    static const string empty_str;
    auto it = params.find(key);
    if (it == params.end()) {
      return empty_str;
    }
    return it->second;
  }
  long long number(const string &key, long long default_value = 0) {
    auto it = params.find(key);
    if (it == params.end()) {
      return default_value;
    }
    return atoi(it->second.c_str());
  }
};
//

namespace appenv {
// 起動引数
int g_k_parameter = 4;
} // namespace appenv

// ----------------------------------------------------------------------------

// グリッドのサイズ
constexpr int N = 10;
// 操作回数最大
constexpr int T = 1000;

// オンラインクエリなら不要
// オフラインクエリなら実装する
struct PInput {
  F<int> grid;
};

struct PAnswer {
  string commands;
};

// ------------------------------------

class Judge {
public:
  // オフラインクエリなら実装をそのまま使う
  virtual const PInput &input() = 0;
  virtual void output(const PAnswer &ans) = 0;
  virtual int score() = 0;
};

//

class JudgeStdio : public Judge {
  bool loaded_ = false;
  PInput pi_;
  int score_ = 0;

public:
  const PInput &input() override {
    if (loaded_)
      return pi_;
    int n, t;
    scanner >> n >> t;
    assert(n == N && t == T);
    pi_.grid.resize(N, N);
    repeat(y, N) {
      repeat(x, N) {
        int a;
        scanner >> a;
        pi_.grid(y, x) = a;
      }
    }
    loaded_ = true;
    return pi_;
  }

  void output(const PAnswer &ans) override {
    for (char c : ans.commands) {
      printer << c << "\n";
    }
  }

  int score() override { return 0; }
};

// ----------------------------------------------------------------------------

struct Emulator {
  F<int> grid_;
  P current_pos_;
  bool error_ = false;
  int value_ = 0;

  Emulator(const PInput &input) : grid_(input.grid), current_pos_(0, 0) {}

  P getCurrentPosition() const { return current_pos_; }

  bool hasError() const { return error_; }

  int getValue() const { return value_; }

  void applyCommand(char command) {
    if (error_)
      return;

    switch (command) {
    case 'U':
      if (grid_.safe(current_pos_.y - 1, current_pos_.x)) {
        current_pos_.y -= 1;
      } else {
        error_ = true;
      }
      break;
    case 'D':
      if (grid_.safe(current_pos_.y + 1, current_pos_.x)) {
        current_pos_.y += 1;
      } else {
        error_ = true;
      }
      break;
    case 'L':
      if (grid_.safe(current_pos_.y, current_pos_.x - 1)) {
        current_pos_.x -= 1;
      } else {
        error_ = true;
      }
      break;
    case 'R':
      if (grid_.safe(current_pos_.y, current_pos_.x + 1)) {
        current_pos_.x += 1;
      } else {
        error_ = true;
      }
      break;
    case 'W':
      grid_(current_pos_) ^= value_;
      break;
    case 'C':
      value_ ^= grid_(current_pos_);
      break;
    default:
      error_ = true; // 不明なコマンド
    }
  }
};

string genereteCommandMoveTo(P curr, P target) {
  string commands;
  while (curr != target) {
    if (curr.y < target.y) {
      commands += 'D';
      curr.y += 1;
    } else if (curr.y > target.y) {
      commands += 'U';
      curr.y -= 1;
    } else if (curr.x < target.x) {
      commands += 'R';
      curr.x += 1;
    } else if (curr.x > target.x) {
      commands += 'L';
      curr.x -= 1;
    }
  }
  return commands;
}

// ----------------------------------------------------------------------------

/*

基本方針
グリッドは忘れていい 実装が面倒なだけ
総和を最大化なので上の方のビットが立っていると嬉しい

すべての要素について一番上のビットが立っている状態にするのは簡単
→ 立っているものを選び、立っていないものにxorしていく

次の手がない。なぜなら、すべての要素で一番上のビットが立っているので、次にxorすると必ず一番上のビットが消滅する
→ No、手持ちの値も xor で編集されるので、なんかそれなりに錬成できる

*/

void applyTo(Emulator &emulator, string &out_commands, const vector<P> &targets,
             char apply_command) {
  for (const P &target : targets) {
    string move_commands =
        genereteCommandMoveTo(emulator.getCurrentPosition(), target);
    for (char command : move_commands) {
      emulator.applyCommand(command);
    }
    emulator.applyCommand(apply_command);
    out_commands += move_commands;
    out_commands += apply_command;
  }
}

// fi: 下からみて最初に立っているビットの位置
bool isValidClz(int value, int fi) {
  if (value == 0)
    return false; // 0は無効
  int clz = countl_zero<uint32_t>(value);
  int x = 31 - clz; // 0-indexed
  return fi == x;
}

// (CurrentValue ^ res1 ^ res2 ^ ...) = 0001xxx..となるような組を探す
// TODO: 改善
vector<P> findBestXorCell(const F<int> &grid, int current_value, int fi) {
  for (int y = 0; y < N; ++y) {
    for (int x = 0; x < N; ++x) {
      P p(y, x);
      if (isValidClz(current_value ^ grid(p), fi)) {
        return {p};
      }
    }
  }
  upto(cnt, 2, 16, 1) {
    repeat(t, 1000) {
      vector<P> candidates;
      int value = current_value;
      repeat(i, cnt) {
        int y = rand(N - 1, N - 1);
        int x = rand(0, N - 1);
        candidates.push_back(P(y, x));
        value ^= grid(P(y, x));
      }
      if (isValidClz(value, fi)) {
        return candidates;
      }
    }
  }
  return {};
}

// (CurrentValue ^ cell) & mask = mask となるような場所をすべて探す
vector<P> findXorCells(const F<int> &grid, int current_value, int mask) {
  vector<P> result;
  for (int y = 0; y < N - 1; ++y) {  // TODO: workaround: 下の方はfindBestXorCellのために無修正
    for (int x = 0; x < N; ++x) {
      P p(y, x);
      if (((current_value ^ grid(p)) & mask) == mask) {
        result.push_back(p);
      }
    }
  }
  return result;
}

template <typename OutputStream>
void printTable(OutputStream &out, const F<int> &grid) {
  for (int y = 0; y < N; ++y) {
    for (int x = 0; x < N; ++x) {
      rrepeat(i, 20) {
        out << !!(grid(y, x) & (1 << i));
      }
      out << ' ';
    }
    out << '\n';
  }
}

string int2bin(int n) {
  string result;
  for (int i = 19; i >= 0; --i) {
    result += !!(n & (1 << i)) + '0';
  }
  return result;
}

// オフラインクエリ用(使うのはPInput)
class SolverOfflineSample {
  const PInput &input_;

  SolverOfflineSample(const PInput &input) : input_(input) {}

  PAnswer solve() {
    string output_commands;

    Emulator emulator(input_);

    int mask = 0;
    rrepeat(i, 20) {
      mask |= 1 << i;
      int printer_mask = 1 << i;

      vector<P> targets =
          findBestXorCell(emulator.grid_, emulator.getValue(), i);
      if (targets.empty()) {
        break;
      }
      applyTo(emulator, output_commands, targets, 'C');

      vector<P> xor_cells =
          findXorCells(emulator.grid_, emulator.getValue(), mask);

      LOG << "mask = " << int2bin(mask)
          << " printer_mask = " << int2bin(printer_mask)
          << " value = " << int2bin(emulator.getValue())
          << " xor_cells.len = " << xor_cells.size() << endl;
      if (xor_cells.empty()) {
        continue;
      }

      applyTo(emulator, output_commands, xor_cells, 'W');

      printTable(clog, emulator.grid_);
    }

    PAnswer ans;
    LOG << "commands.len = " << output_commands.size();
    if (output_commands.size() > T)
    {
      output_commands.resize(T);
    }
    ans.commands = output_commands;

    return ans;
  }

public:
  const static void solve(Judge &judge) {
    const PInput &input = judge.input();
    SolverOfflineSample solver(input);
    judge.output(solver.solve());
  }
};

//

void appMain() {
  JudgeStdio judge;

  SolverOfflineSample::solve(judge);

  // clog << "score = " << judge.score() << endl;
}

//

#define LOAD_CONSTANT_FROM_ARGS(konst, arg)                                    \
  {                                                                            \
    const string &v = CommandLine::get().str(arg);                             \
    if (!v.empty())                                                            \
      konst = atoi(v.c_str());                                                 \
  }

int main(int argc, char **argv) {
  using namespace appenv;
  CommandLine::initialize(argc, argv);
  LOAD_CONSTANT_FROM_ARGS(g_k_parameter, "--a-parater");
  appMain();
  return 0;
}
0