結果

問題 No.1397 Analog Graffiti
ユーザー emthrm
提出日時 2021-02-19 18:43:48
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
(最新)
AC  
(最初)
実行時間 -
コード長 9,423 bytes
コンパイル時間 3,673 ms
コンパイル使用メモリ 246,724 KB
最終ジャッジ日時 2025-01-18 22:58:41
ジャッジサーバーID
(参考情報)
judge2 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2 TLE * 1
other AC * 23 TLE * 1
権限があれば一括ダウンロードができます

ソースコード

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 {
std::vector<int> data;
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)]; }
};
int c;
map<pair<string, char>, pair<vector<int>, unordered_set<int>>> memo1;
pair<vector<int>, unordered_set<int>> f(const string &v, char ub) {
if (memo1.count({v, ub}) == 1) return memo1[{v, ub}];
vector<vector<int>> no(c + 1);
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));
}
return memo1[{v, ub}] = {base.data, emp};
}
int main() {
int r, n; cin >> r >> c >> n;
map<tuple<string, char, int>, ModInt> dp{{{string(c, '0'), '0', 0}, 1}};
ModInt ans = 0;
REP(ri, r + 1) {
map<tuple<string, char, int>, ModInt> nx;
for (auto [fst, pat] : dp) {
auto [v, ub, edge] = fst;
auto [base, emp] = f(v, ub);
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(c * 2 + 1);
REP(j, c * 2 + 1) uf.data[j] = base[j];
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;
}
}
}
char nx_ub = '0' + (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;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0