Solution -「NOI 2017」「洛谷 P3824」泳池
Link.
给定 , 求在一个 的矩阵中, 每个位置的值以 的概率为 , 的概率为 时, 以第一行为边界的最大全 子矩阵大小恰好为 的概率. 答案模 .
把 容斥成 . 令 表示考虑了前 列, 所有合法子矩阵 的概率, 表示一个 列的矩阵, 第一个 出现在第 行, 且 里不存在非法子矩阵的概率. 那么
先来考察 . 枚举第 行上第一个 :
处理 关于 的后缀和 , 不难做到 转移. 当然可以用多项式算法优化.
此后, 我们得到了一个常系数齐次线性递推:
用 LSB-first, 暴力算乘法; 或者用 Fiduccia 都行. 复杂度 .
/* Clearink */
#include <cstdio>
#include <cstring>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
const int MAXK = 1000, MOD = 998244353;
int n, m, p, pwr[MAXK + 5];
int f[MAXK + 5][MAXK + 5], A[MAXK * 2 + 5], F[MAXK * 2 + 5];
inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
inline int mpow( int a, int b ) {
int ret = 1;
for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
return ret;
}
inline int dp( const int i, const int j, const int m ) {
if ( !j ) return 1;
if ( i * j > m ) return 0;
int& cur = f[i][j];
if ( ~cur ) return cur;
cur = mul( pwr[j], dp( i + 1, j, m ) );
rep ( k, 1, j ) {
addeq( cur, mul( mul( pwr[k - 1], sub( 1, p ) ),
mul( dp( i + 1, k - 1, m ), dp( i, j - k, m ) ) ) );
}
return cur;
}
inline void polyMul( const int n, const int m, int& r,
const int* u, const int* v, int* w ) {
static int tmp[MAXK * 2 + 5];
rep ( i, 0, n + m ) tmp[i] = 0;
rep ( i, 0, n ) rep ( j, 0, m ) addeq( tmp[i + j], mul( u[i], v[j] ) );
r = n + m;
rep ( i, 0, r ) w[i] = tmp[i];
}
inline void polyMod( int& n, const int m, int* u, const int* v ) {
per ( i, n, m ) {
if ( !u[i] ) continue;
int coe = u[i];
rep ( j, 0, m ) subeq( u[i - j], mul( coe, v[m - j] ) );
}
n = n < m - 1 ? n : m - 1;
while ( n && !u[n] ) --n;
}
inline int calc( int n, const int m ) {
static int Q[MAXK * 2 + 5], S[MAXK * 2 + 5], G[MAXK * 2 + 5];
memset( Q, 0, sizeof Q );
memset( S, 0, sizeof S );
memset( G, 0, sizeof G );
int lq = m, ls = 0, lg = 1;
Q[m] = 1;
rep ( i, 0, m - 1 ) Q[m - i - 1] = sub( 0, A[i] );
S[0] = G[1] = 1;
for ( ; n; n >>= 1 ) {
if ( n & 1 ) {
polyMul( ls, lg, ls, S, G, S );
polyMod( ls, lq, S, Q );
}
polyMul( lg, lg, lg, G, G, G );
polyMod( lg, lq, G, Q );
}
int ret = 0;
rep ( i, 0, m - 1 ) addeq( ret, mul( F[i], S[i] ) );
return ret;
}
inline int solve( int m ) {
memset( f, 0xff, sizeof f );
dp( 0, m, m );
memset( F, 0, sizeof F ), memset( A, 0, sizeof A );
F[0] = 1, A[0] = sub( 1, p );
rep ( i, 1, m ) {
F[i] = f[0][i];
A[i] = mul( f[1][i], mul( sub( 1, p ), pwr[i] ) );
}
return calc( n, m + 1 );
}
int main() {
int x, y;
scanf( "%d %d %d %d", &n, &m, &x, &y ), p = mul( x, mpow( y, MOD - 2 ) );
pwr[0] = 1;
rep ( i, 1, m ) pwr[i] = mul( pwr[i - 1], p );
printf( "%d\n", sub( solve( m ), solve( m - 1 ) ) );
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2021-08-15 Solution -「Gym 102759F」Interval Graph
2021-08-15 Solution -「Gym 102759C」Economic One-way Roads