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\)。
其中 \(C_i(z) = (1 - z) ^ i (1 + z) ^ {t - i}\),\(C(z) = \sum\limits_{i = 0} ^ t dp_{n, i} C_i(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)}\)。
这时候带入 \(x = 1\) 可得
\(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;
}

浙公网安备 33010602011771号