結果

問題 No.1397 Analog Graffiti
ユーザー 👑 emthrmemthrm
提出日時 2021-02-19 17:58:30
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 9,820 ms / 10,000 ms
コード長 9,185 bytes
コンパイル時間 5,802 ms
コンパイル使用メモリ 247,008 KB
実行使用メモリ 4,384 KB
最終ジャッジ日時 2023-09-16 22:06:14
合計ジャッジ時間 78,924 ms
ジャッジサーバーID
(参考情報)
judge15 / judge12
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,380 KB
testcase_01 AC 2 ms
4,376 KB
testcase_02 AC 9,772 ms
4,380 KB
testcase_03 AC 2 ms
4,380 KB
testcase_04 AC 2 ms
4,376 KB
testcase_05 AC 9,820 ms
4,380 KB
testcase_06 AC 2 ms
4,380 KB
testcase_07 AC 2 ms
4,380 KB
testcase_08 AC 2 ms
4,376 KB
testcase_09 AC 2 ms
4,376 KB
testcase_10 AC 2 ms
4,380 KB
testcase_11 AC 9,550 ms
4,376 KB
testcase_12 AC 1,560 ms
4,380 KB
testcase_13 AC 9,362 ms
4,376 KB
testcase_14 AC 9,339 ms
4,376 KB
testcase_15 AC 30 ms
4,380 KB
testcase_16 AC 1,470 ms
4,376 KB
testcase_17 AC 8,739 ms
4,376 KB
testcase_18 AC 8,948 ms
4,380 KB
testcase_19 AC 8 ms
4,376 KB
testcase_20 AC 10 ms
4,376 KB
testcase_21 AC 61 ms
4,380 KB
testcase_22 AC 3,292 ms
4,384 KB
testcase_23 AC 105 ms
4,376 KB
testcase_24 AC 4 ms
4,376 KB
testcase_25 AC 455 ms
4,380 KB
testcase_26 AC 2 ms
4,376 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,m,n) for(int i=(m);i<(n);++i)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
using ll = long long;
constexpr int INF = 0x3f3f3f3f;
constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr double EPS = 1e-8;
constexpr int MOD = 998244353;
constexpr int dy[] = {1, 0, -1, 0}, dx[] = {0, -1, 0, 1};
constexpr int dy8[] = {1, 1, 0, -1, -1, -1, 0, 1}, dx8[] = {0, -1, -1, -1, 0, 1, 1, 1};
template <typename T, typename U> inline bool chmax(T &a, U b) { return a < b ? (a = b, true) : false; }
template <typename T, typename U> inline bool chmin(T &a, U b) { return a > b ? (a = b, true) : false; }
struct IOSetup {
  IOSetup() {
    std::cin.tie(nullptr);
    std::ios_base::sync_with_stdio(false);
    std::cout << fixed << setprecision(20);
  }
} iosetup;

template <int MOD>
struct MInt {
  unsigned int val;
  MInt(): val(0) {}
  MInt(long long x) : val(x >= 0 ? x % MOD : x % MOD + MOD) {}
  static constexpr int get_mod() { return MOD; }
  static void set_mod(int divisor) { assert(divisor == MOD); }
  static void init(int x = 10000000) { inv(x, true); fact(x); fact_inv(x); }
  static MInt inv(int x, bool init = false) {
    // assert(0 <= x && x < MOD && std::__gcd(x, MOD) == 1);
    static std::vector<MInt> inverse{0, 1};
    int prev = inverse.size();
    if (init && x >= prev) {
      // "x!" and "MOD" must be disjoint.
      inverse.resize(x + 1);
      for (int i = prev; i <= x; ++i) inverse[i] = -inverse[MOD % i] * (MOD / i);
    }
    if (x < inverse.size()) return inverse[x];
    unsigned int a = x, b = MOD; int u = 1, v = 0;
    while (b) {
      unsigned int tmp = a / b;
      std::swap(a -= tmp * b, b);
      std::swap(u -= tmp * v, v);
    }
    return u;
  }
  static MInt fact(int x) {
    static std::vector<MInt> f{1};
    int prev = f.size();
    if (x >= prev) {
      f.resize(x + 1);
      for (int i = prev; i <= x; ++i) f[i] = f[i - 1] * i;
    }
    return f[x];
  }
  static MInt fact_inv(int x) {
    static std::vector<MInt> finv{1};
    int prev = finv.size();
    if (x >= prev) {
      finv.resize(x + 1);
      finv[x] = inv(fact(x).val);
      for (int i = x; i > prev; --i) finv[i - 1] = finv[i] * i;
    }
    return finv[x];
  }
  static MInt nCk(int n, int k) {
    if (n < 0 || n < k || k < 0) return 0;
    if (n - k > k) k = n - k;
    return fact(n) * fact_inv(k) * fact_inv(n - k);
  }
  static MInt nPk(int n, int k) { return n < 0 || n < k || k < 0 ? 0 : fact(n) * fact_inv(n - k); }
  static MInt nHk(int n, int k) { return n < 0 || k < 0 ? 0 : (k == 0 ? 1 : nCk(n + k - 1, k)); }
  MInt pow(long long exponent) const {
    MInt tmp = *this, res = 1;
    while (exponent > 0) {
      if (exponent & 1) res *= tmp;
      tmp *= tmp;
      exponent >>= 1;
    }
    return res;
  }
  MInt &operator+=(const MInt &x) { if((val += x.val) >= MOD) val -= MOD; return *this; }
  MInt &operator-=(const MInt &x) { if((val += MOD - x.val) >= MOD) val -= MOD; return *this; }
  MInt &operator*=(const MInt &x) { val = static_cast<unsigned long long>(val) * x.val % MOD; return *this; }
  MInt &operator/=(const MInt &x) { return *this *= inv(x.val); }
  bool operator==(const MInt &x) const { return val == x.val; }
  bool operator!=(const MInt &x) const { return val != x.val; }
  bool operator<(const MInt &x) const { return val < x.val; }
  bool operator<=(const MInt &x) const { return val <= x.val; }
  bool operator>(const MInt &x) const { return val > x.val; }
  bool operator>=(const MInt &x) const { return val >= x.val; }
  MInt &operator++() { if (++val == MOD) val = 0; return *this; }
  MInt operator++(int) { MInt res = *this; ++*this; return res; }
  MInt &operator--() { val = (val == 0 ? MOD : val) - 1; return *this; }
  MInt operator--(int) { MInt res = *this; --*this; return res; }
  MInt operator+() const { return *this; }
  MInt operator-() const { return MInt(val ? MOD - val : 0); }
  MInt operator+(const MInt &x) const { return MInt(*this) += x; }
  MInt operator-(const MInt &x) const { return MInt(*this) -= x; }
  MInt operator*(const MInt &x) const { return MInt(*this) *= x; }
  MInt operator/(const MInt &x) const { return MInt(*this) /= x; }
  friend std::ostream &operator<<(std::ostream &os, const MInt &x) { return os << x.val; }
  friend std::istream &operator>>(std::istream &is, MInt &x) { long long val; is >> val; x = MInt(val); return is; }
};
namespace std { template <int MOD> MInt<MOD> abs(const MInt<MOD> &x) { return x; } }
using ModInt = MInt<MOD>;

struct UnionFind {
  UnionFind(int n) : data(n, -1) {}

  int root(int ver) { return data[ver] < 0 ? ver : data[ver] = root(data[ver]); }

  bool unite(int u, int v) {
    u = root(u);
    v = root(v);
    if (u == v) return false;
    if (data[u] > data[v]) std::swap(u, v);
    data[u] += data[v];
    data[v] = u;
    return true;
  }

  bool same(int u, int v) { return root(u) == root(v); }

  int size(int ver) { return -data[root(ver)]; }

private:
  std::vector<int> data;
};

int main() {
  int r, c, n; cin >> r >> c >> n;
  map<tuple<string, int, int>, ModInt> dp{{{string(c, '0'), 0, 0}, 1}};
  ModInt ans = 0;
  REP(ri, r + 1) {
    map<tuple<string, int, int>, ModInt> nx;
    vector<vector<int>> no(c + 1);
    for (auto [fst, pat] : dp) {
      auto [v, ub_int, edge] = fst;
      char ub = '0' + ub_int;
      UnionFind base(c * 2 + 1);
      REP(j, c) {
        if (v[j] == '0') {
          base.unite(j, c * 2);
        } else {
          no[v[j] - '0'].emplace_back(j);
        }
      }
      FOR(i, 1, c + 1) {
        FOR(j, 1, no[i].size()) base.unite(no[i][j - 1], no[i][j]);
        no[i].clear();
      }
      unordered_set<int> emp;
      FOR(j, 1, c - 1) {
        if ('1' <= v[j] && v[j] <= ub) emp.emplace(base.root(j));
      }
      REP(i, 1 << c) {
        if (ri == 0 && i == 0) continue;
        if (ri == r && i > 0) break;
        // cout << v << '\n';
        // REP(j, c) cout << (i >> j & 1);
        // cout << '\n';
        UnionFind uf(base);
        int e = edge;
        REP(j, c) {
          if (i >> j & 1) {
            if (v[j] > ub) uf.unite(j, c + j);
            if (j > 0 && (i >> (j - 1) & 1)) uf.unite(c + j - 1, c + j);
          } else {
            if (v[j] <= ub) uf.unite(j, c + j);
            if (j > 0 && !(i >> (j - 1) & 1)) uf.unite(c + j - 1, c + j);
          }
        }
        if (!(i & 1)) uf.unite(c, c * 2);
        if (!(i >> (c - 1) & 1)) uf.unite(c + c - 1, c * 2);
        unordered_set<int> nx_emp{uf.root(c * 2)};
        FOR(j, 1, c - 1) {
          if (!(i >> j & 1)) nx_emp.emplace(uf.root(c + j));
        }
        bool illegal = false;
        for (int e : emp) {
          if (nx_emp.count(uf.root(e)) == 0) {
            illegal = true;
            break;
          }
        }
        if (illegal) {
          // cout << "hall\n";
          continue;
        }
        for (int j = 0; j < c;) {
          if (!(i >> j & 1)) {
            ++j;
            continue;
          }
          e += v[j] <= ub || (j > 0 && v[j - 1] > ub);
          int k = j;
          while (k < c && (i >> k & 1)) {
            e += v[k] <= ub && (k == j || v[k - 1] > ub);
            ++k;
          }
          e += v[k - 1] <= ub || (k < c && v[k] > ub);
          j = k;
        }
        REP(j, c) e += v[j] > ub && !(i >> j & 1) && (j == 0 || v[j - 1] <= ub || (i >> (j - 1) & 1));
        // cout << "edge: " << edge << " -> " << e << '\n';
        if (e > n) continue;
        if (i == 0) {
          if (e < n) continue;
          unordered_set<int> root;
          REP(j, c) {
            if (v[j] > ub) root.emplace(uf.root(j));
          }
          // cout << "connected?: " << (root.size() == 1) << '\n';
          if (root.size() == 1) ans += pat * (r - ri + 1);
        } else {
          unordered_set<int> adj;
          REP(j, c) {
            if (i >> j & 1) adj.emplace(uf.root(c + j));
          }
          REP(j, c) {
            if (v[j] > ub && adj.count(uf.root(j)) == 0) {
              illegal = true;
              break;
            }
          }
          if (illegal) {
            // cout << "separate\n";
            continue;
          }
          string u = "";
          unordered_map<int, int> mp{{uf.root(c * 2), 0}};
          REP(j, c) {
            if (!(i >> j & 1)) {
              int root = uf.root(c + j);
              if (mp.count(root) == 0) {
                int size = mp.size();
                mp[root] = size;
              }
            }
          }
          int nx_ub = mp.size() - 1;
          REP(j, c) {
            if (i >> j & 1) {
              int root = uf.root(c + j);
              if (mp.count(root) == 0) {
                int size = mp.size();
                mp[root] = size;
              }
            }
          }
          REP(j, c) u += '0' + mp[uf.root(c + j)];
          nx[{u, nx_ub, e}] += pat;
          // cout << "next: " << u << '\n';
        }
      }
    }
    dp.swap(nx);
    // for (auto [fst, pat] : dp) {
    //   auto [v, edge] = fst;
    //   cout << v << ' ' << edge << " : " << pat << '\n';
    // }
    // cout << '\n';
  }
  cout << ans << '\n';
  return 0;
}
0