传送门
第一步转换:求恰好为 k 的转换成
≤
k
\le k
≤k 的减去
≤
k
−
1
\le k-1
≤k−1 的
考虑
d
p
dp
dp,令
f
i
f_{i}
fi 表示宽度为
i
i
i 的答案
枚举第一个断点到
i
i
i 的长度,
f
i
=
∑
j
=
0
i
−
1
f
i
−
j
−
1
∗
g
j
∗
(
1
−
p
)
f_i=\sum_{j=0}^{i-1}f_{i-j-1}*g_j*(1-p)
fi=∑j=0i−1fi−j−1∗gj∗(1−p)
g
i
g_i
gi 表示最后一排全部安全,面积
≤
k
\le k
≤k 的概率
g
g
g 好像不是很好求,考虑加上高度一维,
d
p
i
,
j
dp_{i,j}
dpi,j 表示底下宽度为
i
i
i,恰好在
j
+
1
j+1
j+1 行出现了不安全的概率
那么
g
i
=
∑
j
=
1
d
p
i
,
j
g_i=\sum_{j=1}dp_{i,j}
gi=∑j=1dpi,j
考虑
d
p
dp
dp 的转移
套路:枚举第一个不安全的位置,它前面不安全的必须全部
>
j
>j
>j,后面
≥
j
\ge j
≥j
d
p
i
,
j
=
p
j
(
1
−
p
)
∑
l
=
1
i
∑
x
>
j
d
p
l
−
1
,
x
∗
∑
x
≥
j
d
p
i
−
l
,
x
dp_{i,j}=p^j(1-p)\sum_{l=1}^{i} \sum_{x>j}dp_{l-1,x}*\sum_{x \ge j}dp_{i-l,x}
dpi,j=pj(1−p)∑l=1i∑x>jdpl−1,x∗∑x≥jdpi−l,x
有用的状态只有
k
l
o
g
(
k
)
klog(k)
klog(k) 个,前缀和优化转移
f
i
=
g
i
+
∑
j
=
1
i
f
i
−
j
g
j
−
1
(
1
−
p
)
f_i=g_i+\sum_{j=1}^if_{i-j}g_{j-1}(1-p)
fi=gi+∑j=1ifi−jgj−1(1−p)
然后发现
j
j
j 的下届其实是
i
−
k
−
1
i-k-1
i−k−1,然后就可以线性递推了,
k
2
k^2
k2 暴力乘
复杂度
O
(
k
2
l
o
g
(
k
)
+
k
2
l
o
g
(
n
)
)
O(k^2log(k)+k^2log(n))
O(k2log(k)+k2log(n))
#include<bits/stdc++.h>
#define N 1005
using namespace std;
#define cs const
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod;}
int power(int a, int b){int ans=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans;}
void Add(int &a, int b){ a = add(a, b);}
void Mul(int &a, int b){ a = mul(a, b);}
int n, k, x, y, q, pw[N];
int dp[N][N], f[N], g[N];
int p[N], a[N], b[N], tmp[N << 1];
void Mul(int *a, int *b, int *c, int k){
memset(tmp, 0, sizeof(tmp));
int inv = 0, t = k << 1;
for(int i = 0; i < k; i++)
for(int j = 0; j < k; j++) Add(tmp[i + j], mul(a[i], b[j]));
for(int i = t; i >= k; i--) if(tmp[i]){ inv = tmp[i];
for(int j = 0; j <= k; j++) Add(tmp[i-j], Mod - mul(p[k-j], inv));
} for(int i = 0; i < k; i++) c[i] = tmp[i];
}
int Solve(int k){
if(!k) return power(q, n);
memset(dp, 0, sizeof(dp)); memset(f, 0, sizeof(f));
for(int i = 0; i <= 1001; i++) dp[0][i] = 1;
for(int i = 1; i <= k; i++){
for(int j = k/i; j; j--){
for(int l = 1; l <= i; l++) Add(dp[i][j], mul(dp[l - 1][j + 1], dp[i - l][j]));
Mul(dp[i][j], mul(q, pw[j])); Add(dp[i][j], dp[i][j + 1]);
}
}
for(int i = 0; i <= k; i++) g[i + 1] = mul(dp[i][1], q), f[i] = dp[i][1];
for(int i = 1; i <= k; i++)
for(int j = 1, l = min(i, k + 1); j <= l; j++) Add(f[i], mul(f[i - j], g[j]));
memset(p, 0, sizeof(p)); memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b));
p[++k] = 1; for(int i = 0; i < k; i++) p[i] = Mod - g[k - i];
a[0] = b[1] = 1;
for(int i = n; i; i >>= 1, Mul(b, b, b, k))
if(i & 1) Mul(a, b, a, k);
int ans = 0;
for(int i = 0; i < k; i++) Add(ans, mul(a[i], f[i]));
return ans;
}
int main(){
scanf("%d%d%d%d", &n, &k, &x, &y); int p = mul(x, power(y, Mod - 2)); q = add(1, Mod - p);
pw[0] = 1; for(int i = 1; i <= 1000; i++) pw[i] = mul(pw[i-1], p);
cout << add(Solve(k), Mod - Solve(k-1)); return 0;
}