[题解]然然の生日

\[\color{red}{\text{校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\ \begin{array}{|} \hline \color{pink}{\text{The principal is really a god}} \\ \color{pink}{\text{with a closestool on the left and Yongshen on the right}} \\ \color{pink}{\text{holding a sharp pen to pierce the truth}} \\ \color{pink}{\text{Who can resist him? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{green}{\text{校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり}} \\ \color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{lightblue}{\text{Le principal est vraiment un dieu}} \\ \color{lightblue}{\text{avec des toilettes à gauche et Yongshen à droite}} \\ \color{lightblue}{\text{tenant un stylo pointu pour percer la vérité}} \\ \color{lightblue}{\text{Qui peut lui résister ? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\ \color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\ \color{purple}{\text{der einen spitzen Stift hält}} \\ \color{purple}{\text{um die Wahrheit zu durchdringen.}} \\ \color{purple}{\text{Wer kann ihm widerstehen? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{cyan}{\text{Principalis deus est, Yongshen a dextris cum latrina}} \\ \color{cyan}{\text{acuto stylo ad perforandum veritatem: quis resistet ei? }} \\ \hline \end{array} \\ \color{red}{\text{对曰:“无人,狗欲当之,还请赐教!”}} \\ \newcommand\brak[1]{\left({#1}\right)} \newcommand\Brak[1]{\left\{{#1}\right\}} \newcommand\d[0]{\text{d}} \newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}} \newcommand\down[2]{{#1}^{\underline{#2}}} \newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor} \newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil} \newcommand\lcm[0]{\operatorname{lcm}} \newcommand\set[1]{\left\{{#1}\right\}} \newcommand\ceil[1]{\left\lceil{#1}\right\rceil} \newcommand\floor[1]{\left\lfloor{#1}\right\rfloor} \newcommand\rhs[1]{\;\text{Rhs}\;#1} \newcommand\lhs[1]{\;\text{Lhs}\;#1} \newcommand\Vec[1]{\vec{\mathbf{#1}}} \newcommand\rank[0]{\text{rank}} \]




  \(\mathcal{Back\;To\;The\;Menu}\).

2022-03-07 然然の生日

  数组还能开小......焯!

分裂 / Split

  然而我无法证明它的正确性......

  先注意到这样一个事实:对于一个编号为 \(a\) 的球,合并它会减小 \(a-1\) 个,分裂它会增加 \(a\) 个,于是我们合并一个,再分裂一个,消耗总共 \(a+1\)\(a\),就可以获得 \(1\) 的增量,这是特别好的,只要我们拥有足够多的 \(a\),就一定可以凑出 \(n\).

  于是我就有了这种构造:先找到最小的 \(m!\ge n\),然后合并 \(\udiv{m!-n}{m-1}\)\(m^\#\) 球,不难发现现在我们拥有的球数量比 \(n\) 小,并且最多小 \(m-1\) 个,然后再用上述方法一个一个增加。总复杂度应当是 \(\mathcal O(T\log n)\sim \mathcal O(T\log^2n)\) 的。

  至于说证明哪一点呢?就是我无法直接说明用这种构造方法构造不出来的 \(n\) 就一定无解,直到现在也不会......

/** @author __Elaina__ */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define curse(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
template<class T> inline void myswap(T& x, T& y) { x ^= y ^= x ^= y; }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxm = 20;

ll buc[Maxm + 5], n;
int m;

inline void work() {
    memset(buc, 0, sizeof buc);
    readin(n);
    ll dif = 1;
    for (m = 1; dif < n; dif *= (++m));
    // curse("dif == %lld\n", dif);
    if (dif == n) { printf("1\n%d %lld\n", m, dif); return ; }
    buc[m] = dif;
    ll merg = (dif - n + m - 2) / (m - 1);
    dif -= merg * (m - 1), buc[m] -= merg * m, buc[m - 1] += merg;
    // curse("merg == %lld, m == %d, dif == %lld\n", merg, m, dif);
    // rep (i, 1, m) curse("buc[%d] == %lld\n", i, buc[i]);
    bool flg;
    do {
        flg = false;
        for (int i = m; i > 1; --i) {
            while (dif < n && buc[i] >= i + 1) { // merge i, split 1
                buc[i] -= i + 1, ++buc[i - 1], buc[i + 1] += i + 1;
                if (i == m) ++m; // increase the upper limit
                ++dif, flg = true;
            }
        }
        // rep (i, 1, m) curse("buc[%d] == %lld\n", i, buc[i]);
    } while (flg);
    if (dif < n) return void(puts("-1"));
    int cnt = 0;
    rep (i, 1, m) cnt += !!buc[i];
    writln(cnt);
    rep (i, 1, m) if (buc[i]) writln(i, ' '), writln(buc[i]);
}

signed main() {
    freopen("split.in", "r", stdin);
    freopen("split.out", "w", stdout);
    rep (_, 1, readret(1)) work();
    return 0;
}

/**
 * 
 * guess:> at most three kinds of balls
 * merge @p a and split 1, you'll get 1 more ball
 * 
*/

未来 / Future

  一眼就想到平衡三进制,随便把 \(\texttt{rgb}\) 搞个 \(-1,0,1\) 的双射,然后就有 \(f(a,b)=-(a+b)(a\neq b)\),唯一的问题就是当 \(a=b\) 的时候会出问题。然后想到了一个补救方法,不妨先将这个表弄出来:

\[\begin{array}{c:c:c:c} / & -1 & 0 & 1 \\ \hdashline -1 & -1 & 1 & 0 \\ \hdashline 0 & 1 & 0 & -1 \\ \hdashline 1 & 0 & -1 & 1 \end{array} \]

  如果我们将平衡三进制放到 \(\bmod 3\) 下,它就成立了,于是就可以使用 [AGC043B] 123 Triangle 的方法,使用组合数算贡献了。

  对于某两个位置的贡献,实际上是 \((-1)^q{q\choose dis}\) 的,但是要取模 \(3\),想办法让这个取模派上作用,显然想到了 Lucas 定理,如果我们每次将 \(m\) 的执行次数定为 \(3^k\),那么只有当 \(dis=0/3^k\) 时这个系数才会有值,所以我们可以采取将 \(m\) 三进制分解的方法,因此复杂度就是 \(\mathcal O(n\log m)\) 的了。

/** @author __Elaina__ */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define curse(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
template<class T> inline void myswap(T& x, T& y) { x ^= y ^= x ^= y; }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 5e5;

namespace rubbish {

const int Mod = 1e9 + 9;
const int Bit = 19270813;

char reci[Maxn + 5];
int mapsto[256];
char _map[3];
int f[Maxn + 5], n;
ll m;

inline void input() {
    mapsto['r'] = -1, mapsto['g'] = 0, mapsto['b'] = 1;
    _map[0] = 'r', _map[1] = 'g', _map[2] = 'b';
    cin >> n >> m >> reci + 1;
    rep (i, 1, n) f[i] = mapsto[reci[i]];
}

inline ull haxi(int t) {
    ull ret = 0;
    for (int i = 1; i <= n; ++i) {
        ret = ret * Bit + f[i] + 1;
        if (t == 1) ret %= Mod;
    }
    return ret;
}

map<pair<ull, ull>, int> las;
inline void launch() {
    input();
    ll cir = -1;
    las[{ haxi(0), haxi(1) }] = 0;
    for (ll t = 1; t <= m; ++t) {
        int tmp = f[1];
        repf(i, 1, n) if (f[i] != f[i + 1])
            f[i] = -(f[i] + f[i + 1]);
        f[n] = (f[n] != tmp? -(f[n] + tmp): f[n]);
        pair<ull, ull> h = { haxi(0), haxi(1) };
        if (las.count(h)) {
            cir = t - las[h], m -= t;
            break;
        }
        las[h] = t;
    }
    curse("cir == %d\n", cir);
    if (~cir) {
        m %= cir;
        rep (_, 1, m) {
            int tmp = f[1];
            repf(i, 1, n) if (f[i] != f[i + 1])
                f[i] = -(f[i] + f[i + 1]);
            f[n] = (f[n] != tmp? -(f[n] + tmp): f[n]);
        }
    }
    rep (i, 1, n) printf("%c", _map[f[i] + 1]);
}

} // namespace rubbish

int mapsto[256];
char _map[3];
char reci[Maxn + 5];
int f[Maxn + 5], nxt[Maxn + 5];
int n; ll m;

inline void input() {
    _map[mapsto['r'] = 0] = 'r';
    _map[mapsto['g'] = 1] = 'g';
    _map[mapsto['b'] = 2] = 'b';
    cin >> n >> m >> reci;
    repf(i, 0, n) f[i] = mapsto[reci[i]];
}

inline void solve() {
    while (m) {
        ll p; for (p = 1; p * 3 <= m; p *= 3);
        for (; m >= p; m -= p) {
            repf(i, 0, n) nxt[i] = (3 + 3 - f[i] - f[(i + p) % n]) % 3;
            memcpy(f, nxt, n << 2);
            // repf(i, 0, n) curse("f[%d] == %d\n", i, f[i]);
        }
    }
}

inline void print() {
    repf(i, 0, n) printf("%c", _map[f[i]]);
}

signed main() {
    // freopen("future.in", "r", stdin);
    // freopen("future.out", "w", stdout);
    cin.tie(NULL)->sync_with_stdio(false);
    input();
    solve();
    print();
    return 0;
}

/**
 * 
 * balanced ternary: -1, 0, 1
 * 
 * f(i) -> -(f(i) + f(i + 1)) when f(i) = f(i + 1) don't establish
 * 
 * ex-balanced ternary: 0, 1, 2
 * 
 * f(i) -> -(f(i) + f(i + 1)) mod 3 ESTABLISH!
 * 
 * => coefficient (-1)^k * C(k, dis) mod 3
 * 
 * make k as 3^q to split steps
 * 
 * Lucas' theorem => dis should be 3^k or 0, and coefficient is always -1
 * 
*/

回忆 / Memory

  能不能不要先说个 \(n,m\le 40\) 再说 \(n\times m\le 40\) 好不好(*  ̄︿ ̄)

  原题居然是 Project Sekai Euler 的 P701......原题是所有的格子都有 \(\frac{1}{2}\) 的概率,求 \(E(7,7)\),算是一种特殊情况吧。

  每个部分分都说一下吧:

Subtask 1 [Case 1]

  数一下最大的 \(1\) 连通块就行了。

Subtask 2 [Case 2]

  设 \(f(i,j,k)\) 表示前 \(i\) 个格子,第 \(i\) 个是黑色的,并且当前长度为 \(j\),最长长度为 \(k\) 时的概率。转移一下就行了。

Subtask 3 [Case 3~5(8)]

  用 \(\mathcal O(2^{nm})\) 枚举每一种状态就行了,最后能不能跑完 Case 8 就看你的常数了。

Subtask 4 [Case 9]

  不会有人把 \(m=20\) 拿来状压吧......显然将 \(n=2\) 这一维拿来状压,设 \(f(i,j,k,S)\) 表示到第 \(i\) 层,当前连通块大小为 \(j\),当前最大连通块大小为 \(k\),当前层状态为 \(S\) 时的概率。转移的时候枚举两层的状态就行了。

  这一组的特别之处在于,对于每个维护时刻的当下,总是只有最多一个连通块。

Subtask 5 [Case 10,11]

  稍有困难之处,即

  1. 有可能当下存在两个连通块;
  2. 有可能第 \(1,3\) 列的中间在当下被隔开,但是在前面他们是连在一起的;

  状态瞬间变得复杂......其实只需要在 Subtask 4 上附加一维表示 \(1,3\) 是否连接在一起,再将 \(j\) 改装一下,如果 \(1,3\) 分属不同的连通块,我们应当可以从 \(j\) 这一维中获得两个块分别的大小。

  状态复杂,可以用 map 或者 hash 表存状态。

Subtask 6 [Case 12~20]

  终焉の情况!

  我们发现,当列数变得多时,再朴素地增加维数以记录连通性似乎并不是一个好办法,于是我们想到了使用最小表示法记录当前层的哪些位置分属哪些块。

  考虑定义状态 \(dp(S,T,k)\) 表示当下的连通性最小表示法是 \(S\),而每个集合的大小对应的集合是 \(T\),当前最大的连通块大小是 \(k\) 的概率。转移只需要枚举下一层的状态 \(S'\),即可获得下一层的 \(T'\)\(k'\).

  \(\textsf{PlayShe}\) 的实现十分暴力,祂将 \(S,T\) 全部用 vector 存下来,然后用 map 套在外面......

  至于上述状态有多少,这个我也说不清,题解给的极限状态数是 \(162631(n=m=6)\).

/** @author __Elaina__ */

#pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define curse(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Mod = 998244353;
const int Maxn = 40;

int n, m;
int a[Maxn + 5][Maxn + 5];

inline void input() {
    readin(n, m);
    repf(i, 0, n) repf(j, 0, m) readin(a[i][j]);
    if (n < m) {
        static int b[Maxn + 5][Maxn + 5];
        memcpy(b, a, sizeof a);
        memset(a, 0, sizeof a);
        repf (i, 0, n) repf (j, 0, m) a[j][i] = b[i][j];
        swap(n, m);
    }
    // repf (i, 0, n) repf (j, 0, m) curse("a[%d, %d] == %d\n", i, j, a[i][j]);
}

typedef pair<pair<vset, vset>, int> state;

map<state, int> f, tmp;

bool used[Maxn + 5];
int enid[Maxn + 5];

int fa[Maxn + 5];
inline void init(int n) {
    repf (i, 0, n) fa[i] = i;
}
inline int findfa(int u) {
    while (u ^ fa[u]) u = fa[u] = fa[fa[u]];
    return u;
}
inline void merge(int u, int v) {
    u = findfa(u), v = findfa(v);
    fa[v] = u;
}

inline void solve() {
    int U = 1 << m;
    vset bel, siz;
    repf (s, 0, U) {
        bel.clear(); bel.resize(m, -1);
        siz.clear();
        int cnt = 0, prod = 1;
        repf (j, 0, m) {
            if (s >> j & 1) prod = 1ll * prod * a[0][j] % Mod;
            else prod = 1ll * prod * (1ll + Mod - a[0][j]) % Mod;
        }
        if (!prod) continue; // useless
        for (int l = 0, r; l < m; l = r) {
            r = l + 1;
            if ((s >> l & 1) ^ 1) continue; // 0 at this position
            while (s >> r & 1) ++r;
            repf (i, l, r) bel[i] = cnt;
            siz.push_back(r - l), ++cnt;
        }
        int mx = siz.empty()? 0: *max_element(siz.begin(), siz.end());
        auto cur = state{{bel, siz}, mx};
        (f[cur] += prod) %= Mod;
    }
    repf (row, 1, n) {
        // curse("f.size() == %d\n", f.size());
        // tmp.clear(); // clear the next array
        for (const auto& ele: f) {
            const auto& st = ele.fi;        ///< the current 
            const auto& p = ele.se;         ///< probability of @p st
            const auto& pre = st.fi.fi;     ///< the belonging of the last layer
            const auto& pre_sz = st.fi.se;  ///< the size of each block in the last layer
            repf (s, 0, U) { // enumerate the state of next layer
                int las = pre_sz.size(), prod = p;
                repf (j, 0, m) {
                    if (s >> j & 1) prod = 1ll * prod * a[row][j] % Mod;
                    else prod = 1ll * prod * (1ll + Mod - a[row][j]) % Mod;
                }
                if (!prod) continue; // useless
                memset(enid, 0xff, m << 2);
                init(las); // initialize the ufs
                for (int l = 0, r; l < m; l = r) { // merge the color first
                    r = l + 1;
                    if ((s >> l & 1) ^ 1) continue; // 0 at this position
                    while (s >> r & 1) ++r;
                    int id = -1;
                    repf (i, l, r) {
                        if (~pre[i]) {
                            if (~id) merge(id, pre[i]);
                            else id = pre[i];
                        }
                    }
                    repf (i, l, r) enid[i] = id;
                }
                bel.clear(); bel.resize(m, -1);
                siz.clear(); int cnt = 0;
                static bool cnted[Maxn + 5];
                memset(used, false, m);
                memset(cnted, false, las);
                repf (i, 0, m) if (!used[i] && s >> i & 1) {
                    if (!~enid[i]) { // no last layer's connection
                        int r = i;
                        while (r + 1 < m && (s >> (r + 1) & 1)) ++r;
                        rep (j, i, r) bel[j] = cnt, used[j] = true;
                        siz.push_back(r - i + 1), ++cnt;
                    }
                    else {
                        int id = findfa(enid[i]), sum = 0;
                        repf (j, 0, m) if (~enid[j] && findfa(enid[j]) == id) {
                            ++sum, bel[j] = cnt, used[j] = true;
                            if (~pre[j] && !cnted[pre[j]])
                                sum += pre_sz[pre[j]], cnted[pre[j]] = true;
                        }
                        siz.push_back(sum), ++cnt;
                    }
                }
                int mx = siz.empty()? 0: *max_element(siz.begin(), siz.end());
                chkmax(mx, ele.fi.se);
                auto cur = state{{bel, siz}, mx};
                (tmp[cur] += prod) %= Mod;
            }
        }
        f = move(tmp);
        // curse("tmp.size == %d\n", (int)tmp.size());
    }
}

inline void calc() {
    // curse("f.size() == %d\n", f.size());
    int ans = 0;
    for (const auto& ele: f)
        ans = (0ll + ans + 1ll * ele.fi.se * ele.se % Mod) % Mod;
    writln(ans);
}

signed main() {
    freopen("memory.in", "r", stdin);
    freopen("memory.out", "w", stdout);
    input();
    solve();
    calc();
    return 0;
}
posted @ 2022-03-14 22:11  Arextre  阅读(65)  评论(0编辑  收藏  举报