附上学习的博客:https://blog.csdn.net/u013534123/article/details/102762673

大致题意:一个迷宫,里面有很多箱子,你可以向右或者向下走。当你遇到一个或者多个箱子的时候,你可以把箱子往你移动的方向推动,但是不能把箱子推出到墙壁外面。你从左上角出发,问你有多少种方法到右下角。

考虑如果没有箱子,那么就是一个很简单的递推问题,对于一个格子,要么从上面要么从左边来。有箱子的话,由于箱子可以被推动而且不能推到外面,所以我们要考虑是否可以从上面或者下面过来。

还是一样考虑dp,令dp[i][j][0]表示走到位置(i,j)且最后一步是从左边过来的方案,同理dp[i][j][1]表示最后一步从上面来的方案数。然后转移的话,考虑如果是从上面来,我们可以枚举最后一次向右走的位置k,即从(k,j)到(i,j)是一直往下走。如此我们只需要判断是否可以走过来,也即判断(k,j)往下的石头数目是否大于(i,j)下方的格子数,如果大于,那么说明是可以走到(i,j)的,那么把方案数dp[k][j][0]。同理可以得出从左边来,方案数就是dp[i][k][1]。于是有转移方程:

x和y分别表示最前的一个位置,且从这个位置开始到那一行或者那一列的最后的石头数目小于等于后面允许放石头的格子数目。x和y可以用二分比较快速的求,然后显然可以用前缀和来优化,于是复杂度就是O(N^2logN)。然后,仔细想想可以发现x和y是有单调性的,于是可以进一步优化到O(N^2),但是考虑到并没有这个必要而且会复杂一点所以我就没有写了。具体见代码:
——————以上是博客的解法

我另外补充下:

#include<bits/stdc++.h>
#define fi first
#define se second
#define LL long long
#define pb push_back
#define INF 0x3f3f3f3f
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std; const int N = 2010;
const int mod = 1e9 + 7; int dp[N][N][2],sum[N][N][2],R[N][N][2];
char s[N][N]; int main()
{
int n,m;
scc(n,m);
if(n==1&&m==1)
{
puts("1");
return 0;
}
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
for(int j=0;s[i][j];j++)
if (s[i][j]=='R') R[i][j][0]=R[i][j][1]=1;
}
for(int i=0;i<n;i++)
for(int j=1;j<m;j++)
R[i][j][0]+=R[i][j-1][0];//前缀和表示到列到该点的石头
for(int i=0;i<m;i++)
for(int j=1;j<n;j++)
R[j][i][1]+=R[j-1][i][1];
sum[0][0][0]=sum[0][0][0]=1;
dp[0][0][0]=dp[0][0][1]=1;
for(int i=1;i<n;i++)
{
if (R[n-1][0][1]<=n-i-1) //因为石头只能推到边不能出界,例如该列五个格子有两个格子有石头,那你肯定有效格数到3这一个嘛
dp[i][0][1]+=dp[i-1][0][1];
sum[i][0][0]=dp[i][0][1];//为什么sum的第三维是0呢?请看上图公式
}
for(int i=1;i<m;i++)
{
if (R[0][m-1][0]<=m-i-1)
dp[0][i][0]+=dp[0][i-1][0];
sum[0][i][1]=dp[0][i][0];
}
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
int l=0,r=i-1,mid,t,res=-1;
while(l<=r)//二分找找到第某行,该行小于等于后面允许放石头的格子数目
{
mid=l+r>>1;
t=R[n-1][j][1]-R[mid][j][1];
if (t<=n-i-1) res=mid,r=mid-1;
else l=mid+1;
}
if(res>=0)
{
int tmp=res==0?0:sum[res-1][j][1];
dp[i][j][1]=(sum[i-1][j][1]-tmp+mod)%mod;//前缀和基操,
}
sum[i][jd][0]=(sum[i][j-1][0]+dp[i][j][1])%mod;
l=0,r=j-1,res=-1;
while(l<=r)
{
mid=l+r>>1;
t=R[i][m-1][0]-R[i][mid][0];
if (t<=m-j-1) res=mid,r=mid-1;
else l=mid+1;
}
if (res>=0)
{
int tmp=res==0?0:sum[i][res-1][0];
dp[i][j][0]=(sum[i][j-1][0]-tmp+mod)%mod;
}
sum[i][j][1]=(sum[i-1][j][1]+dp[i][j][0])%mod;
}
printf("%d\n",(dp[n-1][m-1][0]+dp[n-1][m-1][1])%mod);
}

  

cf rock is push 【dp】的更多相关文章

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

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

  2. Kattis - honey【DP】

    Kattis - honey[DP] 题意 有一只蜜蜂,在它的蜂房当中,蜂房是正六边形的,然后它要出去,但是它只能走N步,第N步的时候要回到起点,给出N, 求方案总数 思路 用DP 因为N == 14 ...

  3. HDOJ 1423 Greatest Common Increasing Subsequence 【DP】【最长公共上升子序列】

    HDOJ 1423 Greatest Common Increasing Subsequence [DP][最长公共上升子序列] Time Limit: 2000/1000 MS (Java/Othe ...

  4. HDOJ 1501 Zipper 【DP】【DFS+剪枝】

    HDOJ 1501 Zipper [DP][DFS+剪枝] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...

  5. HDOJ 1257 最少拦截系统 【DP】

    HDOJ 1257 最少拦截系统 [DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...

  6. HDOJ 1159 Common Subsequence【DP】

    HDOJ 1159 Common Subsequence[DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...

  7. HDOJ_1087_Super Jumping! Jumping! Jumping! 【DP】

    HDOJ_1087_Super Jumping! Jumping! Jumping! [DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: ...

  8. POJ_2533 Longest Ordered Subsequence【DP】【最长上升子序列】

    POJ_2533 Longest Ordered Subsequence[DP][最长递增子序列] Longest Ordered Subsequence Time Limit: 2000MS Mem ...

  9. HackerRank - common-child【DP】

    HackerRank - common-child[DP] 题意 给出两串长度相等的字符串,找出他们的最长公共子序列e 思路 字符串版的LCS AC代码 #include <iostream&g ...

随机推荐

  1. C#中try catch中throw ex和throw方式抛出异常有何不同_异常捕获堆栈丢失问题

    前言,最近遇到一个使用try-catch异常捕获后记录一下日志,然后再抛出该异常后,异常堆栈里无法显示准确的堆栈地址的问题?   其实以前也遇到过类似问题,没有重视,这次好好研究了下,并上度娘上找了找 ...

  2. .NET 的未来:.NET 5

    前言 不知不觉中,.NET Framework 已经更新到 4.8,.NET Core 也更新到了 3.0 版本.那么 .NET 的未来怎么样呢? 计划 2019 年 Build 大会上,微软宣布下一 ...

  3. tf.nn.in_top_k的用法

    tf.nn.in_top_k组要是用于计算预测的结果和实际结果的是否相等,返回一个bool类型的张量,tf.nn.in_top_k(prediction, target, K):prediction就 ...

  4. Netty服务端NioEventLoop启动及新连接接入处理

    一 Netty服务端NioEventLoop的启动 Netty服务端创建.初始化完成后,再向Selector上注册时,会将服务端Channel与NioEventLoop绑定,绑定之后,一方面会将服务端 ...

  5. 一些实用的Django+HTML设置

    一.关于引入变量 1.变量引入方法: {% block 块名称 %} <p>{{变量名}}<p> {% endblock %} 2.引入变量的值中标签是否转义: 不转义: {% ...

  6. SharePoint 2019 里安装FlowPortal6.00c报错

    环境: Windows Server 2016+SharePoint 2019 安装FlowPortal 6.00c后应用程序池FlowPortal.net 6.x AppPool自动停止. 事件查看 ...

  7. Pumpkin Raising Walk Through

    概述: 这个靶机的规则是根据提示获取南瓜的seed,然后根据一次获取的seed 登录服务器并完成提权,里面涉及到一些CTF的知识,加密解密,提权! 主机端口扫描: ╰─ nmap -p1-65535 ...

  8. SpringCloud之Hystrix:集群容错框架

    分布式环境中,可能会有一些被依赖的服务会失效,影响系统的稳定运行.Hystrix通过添加延迟阈值以及容错的逻辑,以控制分布式系统间组件的交互.Hystrix通过隔离服务间的访问点.停止它们之间的级联故 ...

  9. 使用Python轻松批量压缩图片

    在互联网,图片的大小对一个网站的响应速度有着明显的影响,因此在提供用户预览的时候,图片往往是使用压缩后的.如果一个网站图片较多,一张张压缩显然很浪费时间.那么接下来,我就跟大家分享一个批量压缩图片的方 ...

  10. python 基础学习笔记(6)--函数(1)

    ## **函数(1)** **函数的定义:** 1. [ ] 小时候大家应该都玩过乐高积木,只要通过想象和创意,可以用它怕拼凑出很多神奇的东西.随着学习的深入,编写的代码日益增加并且越来越复杂,所以需 ...