Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P6899 [ICPC2014 WF]Pachinko

P6899 [ICPC2014 WF]Pachinko

经典的随机游走模型。

$f _ i$ 表示 $i$ 可以分给周围的点的概率,显然可以从周围四个点转移,以及第一行的初始概率。按照从上到下从左到右的顺序编号,可以保证方程为一个带长度不超过 $w$ 的带状矩阵,每次在范围内消元即可保证时间复杂度,将矩阵映射到一个集中的空间可以保证空间复杂度。

注意到一个坑点,例如数据:

1
2
3
3 2 25 25 25 25
.XX
.XT

此时方程有:
$$
\begin {cases}
f _ 1 = f _ 2 + 1 \\
f _ 2 = f _ 1 \\
f _ 3 = 0
\end {cases}
$$
我们需要的答案为 $f _ 3$ ,显然可以直接得到答案,但是发现 $f _ 1, f _ 2$ 消元时是无解的,如果没有处理好,我们会得到 $nan$ 的答案。如果出现这样的情况,在图上的体现就是一个点在第一行,和若干的点形成一个连通块,但是这个连通块没有洞,这对答案是没有影响的,所以一旦遇到直接 continue

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
template <class Type>
void read(Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 3) + (x << 1) + c - '0';
flag && (x = ~x + 1);
}
template <class Type>
void write(Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar(x % 10 + '0');
}
const double eps = 1e-10;
const int N = 1e4 + 10, M = 30, dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
bool q[N][M];
int n, m, tot, mv[N * M], id[N][M];
double tA[N * M][M << 1], B[N * M];
double &A (int x, int y)
{
return tA[x][y - mv[x]];
}
bool inside (int a, int b)
{
return a >= 0 && b >= 0 && a < n && b < m;
}
void Gauss ()
{
for (int k = 0; k < tot; k++)
{
if (fabs(A(k, k)) < eps)
continue;
int t = min(tot - 1, k + m);
B[k] /= A(k, k);
for (int i = t; i >= k; i--)
A(k, i) /= A(k, k);
for (int i = k + 1; i <= t; i++)
{
B[i] -= B[k] * A(i, k);
for (int j = t; j >= k; j--)
A(i, j) -= A(k, j) * A(i, k);
}
}
for (int i = tot - 1; ~i; i--)
for (int j = i + 1; j <= min(tot - 1, i + m); j++)
B[i] -= A(i, j) * B[j];
}
int main ()
{
read(m), read(n);
int p[4];
for (int i = 0; i < 4; i++)
read(p[i]);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
char c = getchar();
while (c != 'X' && c != 'T' && c != '.')
c = getchar();
id[i][j] = c != 'X' ? tot++ : -1;
c == 'T' && (q[i][j] = true);
}
for (int i = 0; i < tot; i++)
mv[i] = max(0, i - m);
double st = 0;
for (int i = 0; i < m; i++)
st += id[0][i] != -1;
st = 1 / st;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
if (id[i][j] == -1)
continue;
int &t = id[i][j];
!i && (B[t] = st);
A(t, t) = 1;
if (q[i][j])
continue;
int ps = 100;
for (int k = 0; k < 4; k++)
{
int nx = i + dx[k], ny = j + dy[k];
if (!inside(nx, ny) || id[nx][ny] == -1)
ps -= p[k];
}
for (int k = 0; k < 4; k++)
{
int nx = i + dx[k], ny = j + dy[k];
if (inside(nx, ny) && ~id[nx][ny])
A(id[nx][ny], t) = -(double)p[k] / ps;
}
}
Gauss();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
q[i][j] && printf("%.9lf\n", B[id[i][j]]);
return 0;
}