深海少女与胖头鱼
题目链接
期望DP。考场上没想出来,考完机房里一个大佬给我讲的%%%。
(f[n][m])表示击败(n)个带圣盾的和(m)个不带圣盾的所需要的期望攻击次数,可以列出DP转移方程:(f[n][m] = frac{n}{n + m} f[n + m - 1][1] + frac{m}{n + m} f[n][m - 1] + 1)。
应该还挺好理解的:如果本次攻击了带圣盾的,那么这只带圣盾的会变成一只普通的,其他所有的都会带上圣盾;如果攻击了没有带圣盾的,那么将会减少一只胖头鱼。
然后我们带一下特殊解,当(m = 0)时,(f[n][0] = f[n - 1][1] + 1)。
当(m = 1)时,(f[n][1] = frac{n}{n+ 1}f[n][1] + frac{1}{n + 1} f[n][0] + 1),然后两边同乘一个(n +1),再移项可以得到:
(f[n][1] = f[n][0] + n + 1 = f[n - 1][1] + n + 2 = frac{n ^ 2 + 5n + 2}{2}),那么(f[n][0])也可以带入得到:(f[n][0] = frac{n ^ 2 + 3n}{2})。
然后我们看最上面那个DP转移方程,(n)那一维可以省去,前半部分可以(O(1))求,后半部分递推求就好了。复杂度(O(m logn))
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1e6 + 5, mod = 998244353;
int f, n, m, inv2, inv[N];
int ksm(int x, int y, int mod) {
int res = 1;
while(y) {
if(y & 1) res = 1ll * res * x % mod;
x = 1ll * x * x % mod; y >>= 1;
}
return res;
}
int calc_frac(int x, int y) {
return 1ll * x * y % mod;
}
int calc(int x) {
return (1ll * x * x % mod + 1ll * 5 * x % mod + 2) % mod * inv2 % mod;
}
void make_pre(int x) {
for(int i = 1;i <= x; i++) inv[i] = ksm((n + i) % mod, mod - 2, mod);
}
int main() {
n = read() % mod; m = read(); inv2 = ksm(2, mod - 2, mod);
make_pre(m);
f = (1ll * n * n % mod + 1ll * 3 * n % mod) % mod * inv2 % mod;
for(int i = 1;i <= m; i++)
f = (1ll * calc((n + i) % mod - 1) * calc_frac(n, inv[i]) % mod + 1ll * calc_frac(i, inv[i]) * f % mod + 1) % mod;
printf("%d", f);
return 0;
}