cf rock is push 【dp】
附上学习的博客: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】的更多相关文章
- [CodeForces - 1225E]Rock Is Push 【dp】【前缀和】
[CodeForces - 1225E]Rock Is Push [dp][前缀和] 标签:题解 codeforces题解 dp 前缀和 题目描述 Time limit 2000 ms Memory ...
- Kattis - honey【DP】
Kattis - honey[DP] 题意 有一只蜜蜂,在它的蜂房当中,蜂房是正六边形的,然后它要出去,但是它只能走N步,第N步的时候要回到起点,给出N, 求方案总数 思路 用DP 因为N == 14 ...
- HDOJ 1423 Greatest Common Increasing Subsequence 【DP】【最长公共上升子序列】
HDOJ 1423 Greatest Common Increasing Subsequence [DP][最长公共上升子序列] Time Limit: 2000/1000 MS (Java/Othe ...
- HDOJ 1501 Zipper 【DP】【DFS+剪枝】
HDOJ 1501 Zipper [DP][DFS+剪枝] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...
- HDOJ 1257 最少拦截系统 【DP】
HDOJ 1257 最少拦截系统 [DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- HDOJ 1159 Common Subsequence【DP】
HDOJ 1159 Common Subsequence[DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- HDOJ_1087_Super Jumping! Jumping! Jumping! 【DP】
HDOJ_1087_Super Jumping! Jumping! Jumping! [DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: ...
- POJ_2533 Longest Ordered Subsequence【DP】【最长上升子序列】
POJ_2533 Longest Ordered Subsequence[DP][最长递增子序列] Longest Ordered Subsequence Time Limit: 2000MS Mem ...
- HackerRank - common-child【DP】
HackerRank - common-child[DP] 题意 给出两串长度相等的字符串,找出他们的最长公共子序列e 思路 字符串版的LCS AC代码 #include <iostream&g ...
随机推荐
- C#通过反射调用类及方法
反射有个典型的应用,就是菜单的动态加载,原理就是通过反射调用某个窗体(类).下面演示一下通过反射调用类及方法: 1.新建一个类,命名为:ReflectionHelper,代码如下: #region 创 ...
- Axure制作dialog效果的动作步骤
1.在Axure中添加一个弹框按钮 2.将动态面版拖动到界面中 3.双击动态面版,双击state 4.拖入一块图片占位符进来 5.设置图片 6.回到上一个界面设置动态面版的大小,使其 ...
- javascript中常见的几种循环遍历
项目开发中,不管是建立在哪个框架基础上,对数据的处理都是必须的,而处理数据离不开各种遍历循环.javascript中循环遍历有很多种方式,记录下几种常见的js循环遍历. 一.for循环 for循环应该 ...
- CLAMP 1.0.1 Vulnhub Walkthrough
主机层面端口扫描探测: ╰─ nmap -p1-65535 -A -sV 10.10.202.137 访问web服务 使用dirbuster 加大字段进行目录爆破 http://10.10.202.1 ...
- QT--动态人流量监测系统
QT--动态人流量监测系统 简介: 本项目使用了百度AI的动态人流量监测api,以人体头肩为主要识别目标,适用于低空俯拍,出入口场景,可用于统计当前图像的锁定人数和经过的人数 项目功能 本项目分为相机 ...
- 获取Tekla属性方式
XmlTextWriter xmlTextWriter = new XmlTextWriter((TextWriter) stringWriter); xmlTextWriter.Formatting ...
- [Go]TCP服务中读写进行协程分离
读写两部分进行一下分离,中间通过chan进行传递数据 ,这样可以方便的在write中进行一些业务处理 single/snet/tcpconn.go package snet import ( &quo ...
- Linux系统学习 十七、VSFTP服务—本地用户访问—用户访问控制
FTP相关文件中用户控制列表文件 /etc/vsftpd/ftpusers #该文件永远都是黑名单(针对访问ftp服务,一般不做修改) /etc/vsftpd/user_list ...
- mysql实践:sql优化
---恢复内容开始--- 设计表的时候 1. 不同的表涉及同一个公共意义字段不要使用不同的数据类型(可能导致索引不可用,查询结果有偏差) 2. 不要一张表放太多的数据 主表20~30个字段 ...
- acwing 853. 有边数限制的最短路 模板
地址 https://www.acwing.com/problem/content/description/855/ 给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数. 请你求出 ...