Loading

ARC136F 做题记录

PGF 大好题。link

面对这种时间轴无限长的停时问题,一般使用 PGF 解决。

\(F(x)\) 为从初始状态达到目标状态时的 PGF,\(G(x)\) 为从目标状态达到目标状态时的 PGF,注意这里的到达不一定是第一次。

\(H(x)\) 为从初始状态第一次到达目标状态时的 PGF,那么有 \(H(x) = \dfrac {F(x)} {G(x)}\)

根据 PGF 的性质,答案即为 \(H'(1)\),其中 \(H'(x) = \dfrac {F'(x)G(x) - F(x)G'(x)} {G^2(x)}\)

所以我们只需要求解 \(F(1), F'(1), G(1), G'(1)\),这里以 \(F(1), F'(1)\) 为例,\(G\) 的求解是类似的。

接下来思考如何刻画所有合法的操作,可以枚举从初始状态到目标状态的过程中,有多少个格子 \(0/1\) 发生 flip。设 \(dp_{i, j}\) 表示前 \(i\) 行共 \(j\) 个格子发生了 flip 的方案数,\(\mathcal O(n ^ 2 m ^ 2)\) 求解是容易的。枚举有 \(i\) 个格子,那么这 \(i\) 个格子的操作次数为奇数,其他 \(nm - i\) 个格子的操作次数为偶数。
\(t = nm\)

\[\begin {aligned} \hat F(x) &= \sum_{i = 0} ^ t dp_{n, i} \left (\frac{e ^ {\frac xt} - e ^ {-\frac xt}}2 \right ) ^ i \left ( \frac {e ^ {\frac xt} + e ^ {-\frac xt}} 2 \right ) ^ {t - i} \\ &= \frac 1 {2 ^ t} \sum_{i = 0} ^ t dp_{n, i} \sum_{j = 0} ^ i \binom ij \sum_{k = 0} ^ {t - i} \binom {t - i} k (-1) ^ j e ^ {\frac {(t - 2 (j + k))x} t} \\ &= \frac 1 {2 ^ t} \sum_{k = 0} ^ t e ^ {(1 - \frac {2k} t)x} \sum_{i = 0} ^ t dp_{n, i} \sum_{j = 0} ^ k \binom ij \binom {t - i} {k - j} (-1) ^ j \\ &= \frac 1 {2 ^ t} \sum_{k = 0} ^ t e ^ {(1 - \frac {2k} t)x} [z ^ k]\sum_{i = 0} ^ t dp_{n, i} C_i(z) \\ &= \frac 1 {2 ^ t} \sum_{k = 0} ^ t e ^ {(1 - \frac {2k} t)x} [z ^ k] C(z) \end {aligned}\]

其中 \(C_i(z) = (1 - z) ^ i (1 + z) ^ {t - i}\)\(C(z) = \sum\limits_{i = 0} ^ t dp_{n, i} C_i(z)\)

\[F(x) = \frac 1 {2 ^ t} \sum_{k = 0} ^ t \frac 1 {1 - (1 - \frac {2k} t) x} [z ^ k] C(z) \]

\[F'(x) = \frac 1 {2 ^ t} \sum_{k = 0} ^ t \frac 1 {(1 - (1 - \frac {2k} t) x) ^ 2} [z ^ k] C(z) \]

注意到如果直接带入 \(x = 1\) 时分式 \(\dfrac 1 {1 - x}\) 不可算,所以我们不妨设 \(A(x) = (1 - x) F(x), B(x) = (1 - x) G(x)\),仍然有 \(H(x) = \dfrac {A(x)} {B(x)}\)

\[A(x) = \frac 1 {2 ^ t} \left ([z ^ 0] C(z) + \sum_{k = 1} ^ t \frac {1 - x} {1 - (1 - \frac {2k} t) x} [z ^ k] C(z) \right ) \]

\[\begin {aligned} A'(x) &= \frac 1 {2 ^ t} \sum_{k = 1} ^ t \left (\frac {1 - x} {1 - (1 - \frac {2k} t) x} [z ^ k] C(z) \right )' \\ &= -\frac 1 {2 ^ t} \sum_{k = 1} ^ t \frac {\frac {2k} t} {(1 - (1 - \frac {2k} t) x) ^ 2} [z ^ k] C(z) \end {aligned}\]

这时候带入 \(x = 1\) 可得

\[A(1) = \frac 1{2 ^ t}[z ^ 0] C(z) \]

\[A'(1) = -\frac 1{2 ^ t}\sum_{k = 1} ^ t \frac {t[z ^ k] C(z)} {2k} \]

\(G\) 是同理的,只不过改变了 \(dp\) 数组的值,时间复杂度 \(\mathcal O(n ^ 2 m ^ 2)\)


这里的 PGF 推导有几个 trick 需要学习:

  • 一般设三个 PGF,一个是答案,另外两个来计算答案。

  • 一般处理零因子都是给原 PGF 乘上对应分母,而不是直接在答案分式上下同时乘,虽然本质相同。

  • 长式子的推导:交换枚举顺序;二项式定理合并;其他的组合数与生成函数转化方式。


点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
template <class T>
const inline void rd(T &x) {
    char ch; bool neg = 0;
    while(!isdigit(ch = getchar()))
        if(ch == '-') neg = 1;
    x = ch - '0';
    while(isdigit(ch = getchar()))
        x = (x << 1) + (x << 3) + ch - '0';
    if(neg) x = -x;
}
const ll maxn = 55, inf = 1e9, mod = 998244353, M = 2510;
ll power(ll a, ll b = mod - 2) {
	ll s = 1;
	while(b) {
		if(b & 1) s = 1ll * s * a %mod;
		a = 1ll * a * a %mod, b >>= 1;
	} return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y? x : y; }

ll n, m, t, a[maxn], b[maxn], ans, dp[maxn][M];
char str[maxn]; ll C[M][M], P[M], sum[M];

pir solve(ll *a, ll *b) {
    memset(dp, 0, sizeof dp), dp[0][0] = 1;
    for(ll i = 1; i <= n; i++) {
        for(ll j = 0; j <= (i - 1) * m; j++)
            for(ll k = 0; k <= m - a[i]; k++) {
                ll l = k + a[i] - b[i];
                if(l >= 0)
                    add(dp[i][j + k + l], dp[i - 1][j]
                     * C[m - a[i]][k] %mod * C[a[i]][l] %mod);
            }
    }
    for(ll i = 0; i <= t; i++) P[i] = C[t][i], sum[i] = 0;
    for(ll i = 0; i <= t; i++) {
        if(i) {
            for(ll j = 1; j <= t; j++) add(P[j], mod - P[j - 1]);
            for(ll j = t; j; j--) add(P[j], mod - P[j - 1]);
        }
        for(ll j = 0; j <= t; j++) add(sum[j], P[j] * dp[n][i] %mod);
    }
    pir res; res.fi = sum[0];
    res.se = 0;
    for(ll i = 1; i <= t; i++)
        add(res.se, sum[i] * power(2 * i) %mod);
    res.se = (mod - res.se) %mod * t %mod; return res;
}

int main() {
    rd(n), rd(m), t = n * m, C[0][0] = 1;
    for(ll i = 1; i <= t; i++) {
        C[i][0] = 1;
        for(ll j = 1; j <= i; j++)
            C[i][j] = pls(C[i - 1][j], C[i - 1][j - 1]);
    }
    for(ll i = 1; i <= n; i++) {
        scanf("%s", str + 1);
        for(ll j = 1; j <= m; j++)
            a[i] += str[j] - '0';
    }
    for(ll i = 1; i <= n; i++) rd(b[i]);
    pir F = solve(a, b), G = solve(b, b);
    printf("%lld\n", (F.se * G.fi + mod - G.se * F.fi %mod)
     %mod * power(G.fi, mod - 3) %mod);
	return 0;
}
posted @ 2025-04-11 08:55  Sktn0089  阅读(40)  评论(0)    收藏  举报