在打CF的时候没想到www这个dp真的蛮巧妙的

这是一道dp题(废话

假设我们走到了\((i,j)\)位置,因为我们只能下移/右移,那么我们所有上方与左方的石块(即\(\{ (i,j)|i<n \space || \space j<m \}\)的石块)不管被推到那里都与我无瓜(可以画几张图略推一推,还是比较明显),即该题无后效性,可用dp求解。

合在一起不是很好算,我们可以考虑将右移与下移分开对其进行dp。

因此我们可以用数组\(rs,ds\)来记录某位置右边的石头数量以及下方的石头数量,因为只有这些石头对\((i,j)\)的状态转移有关

设二维状态数组\(r,d\),表示在\((i,j)\)位置时下一步向右(\(r\))或向下(\(d\))走,到达目标位置\((n,m)\)的方案总数,由定义可得\(r[n][m]=d[n][m]=1\)。

重点来惹w:状态转移方程

之所以说这道题巧妙,一是因为它分成了\(r,d\)两块来dp,再一个就是状态转移方程了。

如上图所示,假设我们在黄色格子\((i,j)\),蓝色圆形为石头,虚线为石头移动轨迹。那么易得\(ds[i][j]=1\)(\(rs\)定义忘了的看上文)。因为我们下一步必须向下走,所以我们可以选择连续走\(1\)步、\(2\)步、...一直到\(n-i-ds[i][j]\)步为止,此时下面的石头刚好全部被一个接一个地推到了墙上排好。因此状态转移方程即

\[d[i][j]=\sum_{k=1}^{n-i-ds[i][j]}r[i][j+k]
\]
\[r[i][j]=\sum_{k=1}^{m-i-rs[i][j]}d[i+k][j]
\]

(提前解一个疑:这里对\(r\)数组进行求和而非\(d\)数组求和的原因是我们连续往下走了\(k\)步后下一步应该往右,因此这里用\(r\),反之亦然)

想想还是蛮巧的(或者是窝太弱啦qaq

当然一个一个枚举\(r[i][j+k],d[i+k][j]\)肯定会超时,因此这里我们使用前缀和保存。

注意:代码里的 \(ds,rs\) 及 \(sumd,sumr\) 意义都搞反了( 感谢:@11eyes

code:

#include<bits/stdc++.h>
using namespace std;
long long n , m , r[2100][2100] , d[2100][2100] , ds[2100][2100] , rs[2100][2100];
long long sumr[2100][2100] , sumd[2100][2100];
const int mod = 1e9 + 7;
char s[2100];
//d:down r:right (update:反了
int main()
{
scanf("%d%d" , &n , &m);
for(register int i = 1 ; i <= n ; i++ )
{
scanf("%s" , s + 1);
for(register int j = 1 ; j <= m ; j++ )
{
if(s[j] == 'R') rs[i][j] = 1 , ds[i][j] = 1;
}
}
if(n == 1 && m == 1)
{
cout << (rs[1][1] ^ 1);
return 0;
}
for(register int i = n ; i >= 1 ; i-- )
{
for(register int j = m ; j >= 1 ; j-- )
{
ds[i][j] += ds[i][j + 1];
rs[i][j] += rs[i + 1][j];
}
}
r[n][m] = d[n][m] = sumd[n][m] = sumr[n][m] = 1;
for(register int i = n ; i >= 1 ; i-- )
{
for(register int j = m ; j >= 1 ; j-- )
{
if(i == n && j == m) continue;
r[i][j] = (sumd[i][j + 1] - sumd[i][m - ds[i][j + 1] + 1]) % mod;
d[i][j] = (sumr[i + 1][j] - sumr[n - rs[i + 1][j] + 1][j]) % mod;
sumr[i][j] = (sumr[i + 1][j] + r[i][j]) % mod;
sumd[i][j] = (sumd[i][j + 1] + d[i][j]) % mod;
}
}
/*for(register int i = 1 ; i <= n ; i++ )
{
for(register int j = 1 ; j <= m ; j++ )
{
cout << d[i][j] << ' ';
}
cout << endl;
}
cout << endl;
for(register int i = 1 ; i <= n ; i++ )
{
for(register int j = 1 ; j <= m ; j++ )
{
cout << r[i][j] << ' ';
}
cout << endl;
}*/
// cerr << r[1][1] << " " << d[1][1] << endl;
cout << ((r[1][1] + d[1][1]) % mod + mod) % mod;
return 0;
}

CF1225E题解 Rock Is Push的更多相关文章

  1. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) E. Rock Is Push dp

    E. Rock Is Push You are at the top left cell (1,1) of an n×m labyrinth. Your goal is to get to the b ...

  2. [CodeForces - 1225E]Rock Is Push 【dp】【前缀和】

    [CodeForces - 1225E]Rock Is Push [dp][前缀和] 标签:题解 codeforces题解 dp 前缀和 题目描述 Time limit 2000 ms Memory ...

  3. 【CF1225E Rock Is Push】推岩石

    题目描述 你现在在一个\(n×m\)的迷宫的左上角(即点\((1,1)\)),你的目标是到达迷宫的右下角(即点\((n,m)\)).一次移动你只能向右或者是向下移动一个单位.比如在点\((x,y)\) ...

  4. CF1225E Rock Is Push (计数)

    观察性质计数题orz小贺 考场上跟榜才切 我们只能往下和往右走,那么只有连续的往下和往右可能会造成不合法的情况!如果当前这一步是向右,那么只有它前面连续的一段向右可能影响到它. 考虑把连续的向右/下一 ...

  5. cf rock is push 【dp】

    附上学习的博客:https://blog.csdn.net/u013534123/article/details/102762673 大致题意:一个迷宫,里面有很多箱子,你可以向右或者向下走.当你遇到 ...

  6. Codeforces 1247E. Rock Is Push

    传送门 显然考虑 $dp$ ,设 $fx[i][j]$ 表示从 $(i,j)$ 出发往下走一格,最终到达 $(n,m)$ 的方案数,$fy[i][j]$ 表示从 $(i,j)$ 出发往右走一格,最终到 ...

  7. 【CF1247E】Rock Is Push(DP,二分)

    题意:有一个n*m的方格,每一格可能为空也可能有石头,要从(1,1)走到(n,m),每次可以往右或往下走 每次走的时候都会将自己面前的所有石头向移动方向推一格,如果碰到了边界就推不过去 问方案数模1e ...

  8. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2)

    A - Forgetting Things 题意:给 \(a,b\) 两个数字的开头数字(1~9),求使得等式 \(a=b-1\) 成立的一组 \(a,b\) ,无解输出-1. 题解:很显然只有 \( ...

  9. some problem

    CF1257F Make Them Similar $solution:$ 折半搜索后考虑如何维护两个数组的和,可以将 $A$ 中每个数减 $A_1$ ,$B$ 中每个数被减 $B_1$ ,$map$ ...

随机推荐

  1. 微信小程序setdata修改数组或对象

    1.this.setdata修改数组的固定一项的值 changeItemInArr: function() { this.setData({ 'arr[0].text':'changed data' ...

  2. 微信小程序使用同声传译实现语音识别功能

    我使用同声传译语音识别功能是为了实现微信小程序首页的语音搜索功能,如果你也是那么恭喜你,你可以ctrl+c.ctrl+v再改一改,如果你不是那么你也不要着急的走可以看完我的文章会对你有所帮助! 首先是 ...

  3. Cisco Catalyst 9800-CL Wireless Controller for Cloud

    面向云的思科 Catalyst 9800-CL 无线控制器,专为基于意图的网络全新打造. 版本: C9800-CL-universalk9.17.04.01 (29-Nov-2020) C9800-C ...

  4. tomcat---starup.bat点击窗口自动关闭

  5. TensorRT 数据格式说明

    TensorRT数据格式说明 NVIDIA  TensorRT支持不同的数据格式.需要考虑两个方面:数据类型和布局. 数据类型格式 数据类型是每个单独值的表示.它的大小决定了数值的范围和表示的精度:分 ...

  6. eclipse左边的工程列表窗口不见了解决方案

    解决eclipse左边的工程列表窗口看不到工程目录的方法: Window->Show View->Project Explorer(如果没有Project Explorer选项,则Wind ...

  7. 《python网络数据采集》笔记2

    1.网页表单与登陆窗口 Requests 库擅长处理那些复杂的 HTTP 请求.cookie.header(响应头和请求头)等内容. 1)表单提交 import requests #字段 params ...

  8. Minecraft类游戏地形生成机制

    目录 前言 生成地形高度 生成生物群落 模拟雨水侵蚀.生成河流(未完) 生成洞穴.裂谷 生成植被 放置树木(Bezier曲线) 生成建筑 生成发展域(元胞自动机模型) 放置建筑(DFS) 连接道路(A ...

  9. 狂神说Linux笔记:Vim和账号、用户组、磁盘管理

    什么是Vim编辑器 Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 简单的来说, vi 是老式的字处理器,不过功能已经很齐全了,但 ...

  10. Linux芯片驱动之SPI Controller

    针对一款新的芯片,芯片厂商如何基于Linux编写对应的 SPI controller 驱动? 我们先看看 Linux SPI 的整体框架: 可以看到,最底层是硬件层,对应芯片内部 SPI contro ...