|——>传送门<——|
题目描述
给定一张的网格图,给定机器人起始位置和垃圾位置,每次机器人可以从
向
运动,碰壁后对方向取反。每次可以将移动到的位置所在的横行和竖列清空掉,现在告诉你当机器人与垃圾同行同列时有
概率清掉垃圾。问清理垃圾所需移动次数的期望。
题解
首先,机器人移动的过程一定存在循环节,也就是说从某点出发一直按照题目规则移动,一定会回到该点(证明略)。那么不妨设每步一循环,这
步中有
次与垃圾同行同列。
设表示到第
个点所移动的步数,那么可以列出期望的表达式:
对上式进行化简:
对,设
,等比数列求和后,由于
,故数列收敛,取极限得
。
对,发现为一等差数列项
等比数列项的形式,运用错位相减法求和后同样取极限得
于是可得:
求和得:
那么直接模拟走的轮数求和即可。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
int a[N], b[N];
inline int binpow(int x, int y, int mod, int res = 1){
for (; y; y >>= 1, (x *= x) %= mod) if (y & 1) (res *= x) %= mod;
return res;
}
inline int inv(int x){ return binpow(x, MOD - 2, MOD); }
inline void solve(){
int n, m, rb, cb, rd, cd, p; cin >> n >> m >> rb >> cb >> rd >> cd >> p;
p = p * inv(100) % MOD;
int pre = 1, idx = 0, ans = 0, dr = 1, dc = 1;
map<tuple<int, int, int, int>, bool> mp;
while(true){
if (rb + dr < 1 || rb + dr > n) dr *= -1;
if (cb + dc < 1 || cb + dc > m) dc *= -1;
if (mp[{rb, cb, dr, dc}]) break;
else mp[{rb, cb, dr, dc}] = true;
if (rb == rd || cb == cd) {
ans = (ans + idx * pre % MOD * p % MOD) % MOD;
pre = pre * (1 - p + MOD) % MOD;
}
rb += dr, cb += dc, idx++;
}
ans = ((ans + idx * pre % MOD) % MOD) * inv((1 - pre + MOD) % MOD) % MOD;
cout << ans << endl;
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 0; cin >> t;
while(t--) solve();
return 0;
}