久莲是个爱玩的女孩子。
暑假终于到了,久莲决定请她的朋友们来游泳,她打算先在她家的私人海滩外圈一块长方形的海域作为游泳场。然而大海里有着各种各样的危险,有些地方水太深,有些地方有带毒的水母出没。她想让圈出来的这一块海域都是安全的。
经过初步分析,这块海域可视为一个底边长为 N 米,高为 1001 米的长方形网格。其中网格的底边对应着她家的私人海滩,每一个 1m×1m 的小正方形都代表着一个单位海域。她拜托了她爸爸明天去测量每一个小正方形是否安全。在得知了信息之后,她要做的就是圈出她想要的游泳场啦。
她心目中理想的游泳场满足如下三个条件:
- 必须保证安全性。即游泳场中的每一个单位海域都是安全的。
- 必须是矩形。即游泳场必须是整个网格中的一个 a×b 的子网格。
- 必须和海滩相邻。即游泳场的下边界必须紧贴网格的下边界。
例如:当 N=5 时,若测量的结果如下(因为 1001 太大,这儿只画出网格最下面三行的信息,其他部分都是危险的)
那么她可以选取最下面一行的 1×4 的子海域,也可以选择第三列的 3×1 的子海域。注意她不能选取最上面一行的 1×5 的子海域,因为它没有与海滩相邻。
为了让朋友们玩的开心,她想让游泳场的面积尽可能的大。因此她会选取最下面那一行的 1×4 的子海域作为最终方案。
虽然她要明天才能知道每一个单位海域是否安全,但是她现在就想行动起来估计一下她的游泳场面积有多大。经过简单的估计,她假设每一个单位海域都有独立的 q 的概率是安全的,1−q 的概率是不安全的。她想要知道她能选择的最大的游泳场的面积恰好为 K 的概率是多少。
然而久莲对数学并不感兴趣,因此她想让你来帮她计算一下这个数值。
输入描述
输入一行四个正整数 N,K,x,y,其中 1≤x<y<998244353。q 的取值为 yx。
输出描述
输出一行一个整数表示答案在模 998244353 意义下的取值。
即设答案化为最简分式后的形式为 ba ,其中 a 和 b 的互质。输出整数 x 使得 bx≡amod998244353 且 0≤x<998244353。可以证明这样的整数 x 是唯一的。
样例输入
10 5 1 2
样例输出
342025319
提示
数据范围与提示
测试点编号 | N | K |
---|---|---|
1,2 | =1 | ≤1000 |
3 | ≤10 | ≤8 |
4 | ≤10 | ≤9 |
5 | ≤10 | ≤10 |
6 | ≤1000 | ≤7 |
7 | ≤1000 | ≤8 |
8 | ≤1000 | ≤9 |
9,10,11 | ≤1000 | ≤100 |
12,13,14 | ≤1000 | ≤1000 |
15,16 | ≤109 | ≤10 |
17,18 | ≤109 | ≤100 |
19,20 | ≤109 | ≤1000 |
代码实现如下:
#include <bits/stdc++.h>
using namespace std;
#define Set(a, v) memset(a, v, sizeof(a))
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define Forr(i, a, b) for(int i = (a); i >= (int)(b); --i)
#define N (1000 + 5)
const int P = 998244353;
inline int Mod(int a){
if(a < 0) return a + P;
return a >= P? a - P: a;
}
inline int Mul(int a, int b){
return (long long)a * b % P;
}
inline int Pow(int a, int anum){
int ret = 1;
while(anum){
if(anum & 1) ret = Mul(ret, a);
a = Mul(a, a); anum >>= 1;
}
return ret;
}
int n, x, y, p, q, powq[N], f[N][N], g[N], h[N], b[N], c[N], tmp[N << 1];
void ExpMul(int *A, int *B, int k){
For(i, 0, k) For(j, 0, k) tmp[i + j] = Mod(tmp[i + j] + Mul(A[i], B[j]));
Forr(i, k << 1, k){
For(j, 0, k - 1) tmp[i + j - k] = Mod(tmp[i + j - k] + Mul(tmp[i], g[k - j]));
tmp[i] = 0;
}
For(i, 0, k - 1) A[i] = tmp[i], tmp[i] = 0;
}
void ExpPow(int *A, int anum, int *ret, int k){
while(anum){
if(anum & 1) ExpMul(ret, A, k);
ExpMul(A, A, k); anum >>= 1;
}
}
int Solve(int k){
if(!k) return Pow(p, n);
Set(f, 0); f[k + 1][0] = 1;
Forr(i, k, 1){
int m = min(n, k / i);
f[i][0] = 1;
For(j, 0, m) g[j] = Mul(Mul(f[i + 1][j], powq[j]), p);
For(j, 1, m){
For(t, 0, j - 1) f[i][j] = Mod(f[i][j] + Mul(g[t], f[i][j - t - 1]));
f[i][j] = Mod(f[i][j] + Mul(f[i + 1][j], powq[j]));
}
}
++k;
For(i, 1, k) g[i] = Mul(Mul(f[1][i - 1], powq[i - 1]), p);
h[0] = 1;
For(i, 1, k - 1){
h[i] = Mul(powq[i], f[1][i]);
For(j, 1, i) h[i] = Mod(h[i] + Mul(h[i - j], g[j]));
}
if(n < k) return h[n];
int ret = 0;
Set(b, 0); Set(c, 0); b[0] = c[1] = 1;
ExpPow(c, n, b, k);
For(i, 0, k - 1) ret = Mod(ret + Mul(b[i], h[i]));
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("pool.in", "r", stdin);
freopen("pool.out", "w", stdout);
#endif
int k;
scanf("%d%d%d%d", &n, &k, &x, &y);
q = Mul(x, Pow(y, P - 2)); p = Mod(1 - q);
powq[0] = 1;
For(i, 1, 1000) powq[i] = Mul(powq[i - 1], q);
printf("%d\n", Mod(Solve(k) - Solve(k - 1)));
return 0;
}