Editorial for Danger at the Marks
Submitting an official solution before solving the problem yourself is a bannable offence.
Approach
The input provides a matrix . We can see that
gives us the probability of
ending at position
after
steps, when starting from position
.
For a given start :
(by linearity of expectation)
.
A collision at time occurs precisely when Eric and Lucas occupy the same mark. They
move independently, so the probability they both land at mark
is
,
and summing over
gives the probability of a collision. The same sum is the
entry of
, since
.
The expectation is then . Matrix addition is entrywise, so
this is the
entry of
. (It turns out, entry
gives
us the EV for Lucas starting at
, and Eric starting at
.)
Naively calculating this takes , which is not fast enough. We can find a
recurrence to speed this up.
Define to equal the sum from
to
:
.
is the zero matrix.
when
is odd.
when
is even.
Using this recurrence, and being careful to calculate all required powers of with
matrix multiplications, we can evaluate
in
.
Solution (C++)
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
#define nl '\n'
#define fr first
#define sc second
typedef long long ll;
typedef pair<int, int> pii; typedef vector<int> vi;
const ll mod = 1e9 + 7;
ll modpow(ll a, ll p) {
ll res = 1;
while(p) {
if (p&1)res=res*a%mod;
a=a*a%mod;
p/=2;
}
return res;
}
const ll inv100 = modpow(100, mod-2);
typedef vector<array<ll,100>> mat;
int n;
mat matmul(const mat &a, const mat &b) {
mat res(n);
rep(i,0,n) rep(j,0,n) rep(k,0,n) {
(res[i][j] += a[i][k] * b[k][j]) %= mod;
}
return res;
}
mat matadd(const mat &a, const mat &b) {
mat res(n);
rep(i,0,n) rep(j,0,n) res[i][j] = (a[i][j] + b[i][j])%mod;
return res;
}
// :3
mat trans(const mat &a) {
mat res(n);
rep(i,0,n) rep(j,0,n) {
res[i][j] = a[j][i];
}
return res;
}
mat id;
int main() {
cin.tie(0)->sync_with_stdio(0);
ll k;
cin >> n >> k;
id = mat(n);
rep(i,0,n) id[i][i] = 1;
mat graph(n);
rep(i,0,n) rep(j,0,n) {
cin >> graph[i][j];
(graph[i][j] *= inv100) %= mod;
}
mat grapht = trans(graph);
// graph^k, sum
auto recurse = [&](auto && self, ll k) -> array<mat,2> {
if (k == 0) return {id, mat(n)};
if (k % 2 == 0) {
auto [ha,sum] = self(self, k/2);
auto a = matmul(ha,ha);
auto nw = matmul(matmul(ha, sum), trans(ha));
nw = matadd(nw, sum);
return {a,nw};
} else {
auto [ha,sum] = self(self,k-1);
auto a = matmul(ha,graph);
auto nw = matmul(matmul(graph,sum),grapht);
nw = matadd(nw, matmul(graph,grapht));
return {a,nw};
}
};
auto [a,res] = recurse(recurse,k);
rep(i,1,n) cout << res[i][0] << " \n"[i == n - 1];
}
Comments