题解 CF1225E 【Rock Is Push】
感觉这题非常有趣,尤其是这个样例解释。
这个问题形式上类似格线游走,虽然无法直接使用格线游走的模型解决,仍然可以考虑 DP。
考虑到我们只能向右或向下走,那么如果我们在某一步向右推了一块石头,那么它右边的石头一定都没动过。这启发我们在 DP 中记录最后一步向哪一个方向走。
如果我们仍然一步一步转移,那么会产生一个问题——我们无法得知走到
但是我们又注意到我们在判断
这启发我们枚举最后的连续一段向一个方向走,然后强制上一步往另外一个方向走。可以转移当且仅当最后走的一段上面的石头能够全部被推到目标点下方。
直接转移是
#include <bits/stdc++.h>
using namespace std;
const int mod = 1000000007;
int n, m, dp[2][2005][2005], pres[2][2005][2005];
char mp[2005][2005];
vector <int> rrk[2005], crk[2005];
inline void Read() {
cin >> n >> m;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) cin >> mp[i][j];
}
}
inline void Prefix() {
for (int i = n;i >= 1;i--) {
for (int j = m;j >= 1;j--) {
if (mp[i][j] == 'R') {
rrk[i].push_back(j);
crk[j].push_back(i);
}
}
}
}
inline void Solve() {
if (n == 1 && m == 1) {
cout << 1 << endl;
return;
}
dp[0][1][1] = dp[1][1][1] = 1;
pres[0][1][1] = pres[1][1][1] = 1;
for (int i = 1;i <= n;i++) {
for (int j = 1 + (i == 1);j <= m;j++) {
int lst;
if (m - j >= rrk[i].size()) lst = 1;
else lst = rrk[i][m - j];
dp[0][i][j] = (pres[1][i][j - 1] - pres[1][i][lst - 1] + mod) % mod;
if (n - i >= crk[j].size()) lst = 1;
else lst = crk[j][n - i];
dp[1][i][j] = (pres[0][i - 1][j] - pres[0][lst - 1][j] + mod) % mod;
pres[1][i][j] = (pres[1][i][j - 1] + dp[1][i][j]) % mod;
pres[0][i][j] = (pres[0][i - 1][j] + dp[0][i][j]) % mod;
}
}
cout << (dp[0][n][m] + dp[1][n][m]) % mod << endl;
}
int main() {
std::ios::sync_with_stdio(0);
Read();
Prefix();
Solve();
return 0;
}