题目链接 HDU 6229
题意 在一个$N * N$的格子矩阵里,有一个机器人。
格子按照行和列标号,左上角的坐标为$(0, 0)$,右下角的坐标为$(N - 1, N - 1)$
有一个机器人,初始位置为$(0, 0)$。
现在这个矩阵里面,有一些障碍物,也就是说机器人不能通过这些障碍物。
若机器人当前位置为$(x, y)$,那么他下一个位置有可能为与当前格子曼哈顿距离为$1$的所有格子的任意1个。
也有可能停留在原来的位置$(x, y)$
求经过无限长的时间之后,这个机器人的位置在给定区域的概率。
结果用分数表示。
给定区域为$(x, y)$,满足 $x + y ≥ N - 1$
题目满足无障碍区域是连通的
当时在现场,和Au的差距就是罚时和这道题。
结论其实很简单,但是赛场上因为思维僵化就是想不出来。
首先对于每个点,初始都有一个权值。
角落的权值为$3$,边上但不是角落的权值为$4$,其他点权值为$5$。
我们对每个障碍点进行处理。障碍点的权值直接赋值为$0$,障碍周围的点权值减$1$
由于开不下那么大的二维数组,所以对那些被操作过的点,我们用map记录。
最后把区域内的权值累加,除以整个矩形的权值和即为答案。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
typedef pair <int, int> PII;
const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};
int T;
int n, m;
map < pair <int, int> , LL > mp;
int ca = 0;
inline LL judge(int x, int y){
if ((x == 0 && y == 0) || (x == 0 && y == n - 1) || (x == n - 1 && y == 0) || (x == n - 1 && y == n - 1)) return 3;
if (x == 0 || x == n - 1 || y == 0 || y == n - 1) return 4;
return 5;
}
inline bool check(int x, int y){
return (x + y) >= (n - 1);
}
inline bool ok(int x, int y){
return x >= 0 && y >= 0 && x <= n - 1 && y <= n - 1;
}
LL gcd(LL a, LL b){
return b == 0 ? a : gcd(b, a % b);
}
int main(){
scanf("%d", &T);
while (T--){
scanf("%d%d", &n, &m);
LL all = 4 * 3 + (n - 2) * 4 * 4 + 5 * (n - 2) * (n - 2);
LL xx1 = 3, xx2 = 2 * (n - 2);
LL xx3 = n * (n + 1) / 2 - xx1 - xx2;
LL sum = xx1 * 3 + xx2 * 4 + xx3 * 5;
mp.clear();
while (m--){
int x, y;
scanf("%d%d", &x, &y);
mp[MP(x, y)] = judge(x, y);
rep(i, 0, 3){
int nx = x + dx[i], ny = y + dy[i];
if (ok(nx, ny)){
++mp[MP(nx, ny)];
mp[MP(nx, ny)] = min(mp[MP(nx, ny)], judge(nx, ny));
}
}
}
for (auto cnt : mp){
int x = cnt.fi.fi, y = cnt.fi.se;
LL z = cnt.se;
if (check(x, y)) sum -= z;
all -= z;
}
LL a1 = sum, a2 = all;
LL g = gcd(a1, a2);
a1 /= g, a2 /= g;
printf("Case #%d: %lld/%lld\n", ++ca, a1, a2);
}
return 0;
}