偶然间,chnlich发现了他小时候玩过的一个游戏“魂斗罗”,于是决定怀旧。但是这是一个奇怪的魂斗罗MOD。有N个关卡,初始有Q条命。每通过一个关卡,会得到u分和1条命,生命上限为Q。其中u=min(最近一次连续通过的关数,R)。若没有通过这个关卡,将会失去1条命,并进入下一个关卡。当没有生命或没有未挑战过的关卡时,游戏结束,得到的分数为每关得到的分数的总和。由于chnlich好久不玩这个游戏了,每条命通过每个关卡的概率均为p(0<=p<=1),原先chnlich的最高分纪录是S。现在chnlich想要知道,当p至少为多少时,chnlich期望获得的总分数能够超过原先的最高分。
矩阵乘法优化的dp。
g[i+1][min(j+1,R)][min(k+1),Q]+=g[i][j][k]*p
g[i+1][0][k-1]+=g[i][j][k]*(1-p)
Answer+=g[i][j][k]*p*(j+1)
#include
#include
#include
#include
#include
#include
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
using namespace std;
const int N = 40;
typedef long long LL;
typedef double Mtr[N][N];
int p[7][25], n, R, Q, S, m;
double d;
Mtr A, B, a, b;
void Mul(Mtr &a, Mtr b) {
Mtr c;
memset(c, 0, sizeof(c));
Rep(i, 1, n)
Rep(j, 1, n)
Rep(k, 1, n) c[i][j] += a[i][k] * b[k][j];
Rep(i, 1, n) Rep(j, 1, n) a[i][j] = c[i][j];
}
bool Check(double P) {
memset(a, 0, sizeof(a)), n = 0;
memset(b, 0, sizeof(b));
Rep(i, 0, Q) {
int k = (i == Q) ? R : min(i-1, R);
Rep(j, 0, max(k, 0)) p[i][j] = ++ n;
}
a[1][1] = 1;
Rep(i, 1, Q) {
int k = (i == Q) ? R : min(i-1, R);
Rep(j, 0, max(k, 0)) {
int x = p[i][j], y = p[i-1][0], z = p[min(i+1, Q)][min(j+1, R)];
if (i > 1) a[x][y] = (1 - P);
a[x][z] = P, a[x][1] = P * min((j + 1), R);
}
}
Rep(i, 1, n) b[i][i] = 1;
int y = m;
while (y) {
if (y & 1) Mul(b, a);
Mul(a, a), y /= 2;
}
return b[p[Q][0]][1] > S;
}
int main()
{
scanf ("%d%d%d%d", &m, &R, &Q, &S);
int l = 0, r = 10000000, d = r;
if (!Check(1)) { puts("Impossible."); return 0; }
while (l < r) {
int mid = (l + r) / 2;
double p = double(mid) / d;
if (Check(p)) r = mid;
else l = mid + 1;
}
printf ("%.6f\n", double(l) / d);
return 0;
}