首页 > 其他分享 >题解:CF1225E Rock Is Push

题解:CF1225E Rock Is Push

时间:2024-10-23 14:03:41浏览次数:7  
标签:dpr rs 题解 转移 dpd Push 石头 CF1225E define

很玄妙的一道 dp 题。

Hint

Analysis

首先你要确保你会做当石头没有/固定的情况,这道题其实也是 dp。

考虑石头带来的影响,唯一的作用就是限制你的移动,比方说你下面有 \(3\) 块石头,由于只能向右或向下移动,你实际上往下只能走到当前列第 \(n-3\) 行。

于是对于石头的处理,设 \(rs[i][j]\) 和 \(ds[i][j]\) 为 \((i,j)\) 位置右/下方(包括 \((i,j)\))的石头数量,这两个数组可以用前缀和预处理出来。

我们将石头分成两个方向分别维护,于是也考虑分别设计两个方向的状态。

设 \(dpr[i][j]\) 和 \(dpd[i][j]\) 为在 \((i,j)\) 位置,下一步向右/下走,最终走到 \((n,m)\) 方案数,初始状态 \(dpr[n][m]=dpd[n][m]=1\)。

\(p.s.\) 这里为了方便代码,坐标采用第几行第几列的方式记录,与数学上不同

接着我们来推导 \(dpr[i][j]\) 的状态转移方程:

首先由于我们的初始状态是 \(dpr[n][m]\),所以我们实际上是倒着推的,所以下一步向右走实际上是前一步已经往左走了,于是我们转移所需要的状态在我们的右边,这就是这个状态设计的妙处。

还有,我们认为改变方向才是一次转移,即转移不是只走一格,而是在一条直线上走了一段,接着要改变方向了,才算是一次转移。所以 \(dpr[i][j]\) 应该由它右边的所有可以走到的结点转移来,而又因为我们要改变方向,所以我们应该取这些结点的 \(dpd\) 进行转移,很神奇吧。

最后考虑它右边哪些结点可以走到,这就要看石头了,显然右边有 \(rs[i][j+1]\) 个石头,所以最多走到第 \(m-rs[i][j+1]\) 列。

于是状态转移方程:

\[dpr[i][j]=\sum_{k=j+1}^{m-rs[i][j+1]}dpd[i][k] \]

同理推出 \(dpd[i][j]\) 的状态转移方程:

\[dpd[i][j]=\sum_{k=i+1}^{n-ds[i+1][j]}dpr[k][j] \]

于是两个状态转移方程就都出来了:

\[\begin{cases} dpr[i][j]=\sum_{k=j+1}^{m-rs[i][j+1]}dpd[i][k] \\\\ dpd[i][j]=\sum_{k=i+1}^{n-ds[i+1][j]}dpr[k][j] \end{cases}\]

接着用前缀和优化即可,时间复杂度 \(O(nm)\)。

记得特判 \(n=1\) 且 \(m=1\) 的情况哦。

Code

#include<bits/stdc++.h>
#define pb push_back
#define is insert
#define fi first
#define se second
#define bg begin
#define INF INT_MAX
#define mathmod(a,m) (((a)%(m)+(m))%(m))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N=2005;
const ll MOD=1e9+7;
int n,m,rs[N][N],ds[N][N];
ll dpr[N][N],dpd[N][N],dprs[N][N],dpds[N][N];
char a[N][N];
char gc(){
    char c=getchar();
    while(c==' '||c=='\n'||c=='\r'||c=='\t') c=getchar();
    return c;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=gc();
    if(n==1&&m==1){printf("1");return 0;} // 特判
    // 前缀和预处理
    for(int i=n;i;i--){
        for(int j=m;j;j--){
            rs[i][j]=rs[i][j+1]+(a[i][j]=='R');
            ds[i][j]=ds[i+1][j]+(a[i][j]=='R');
        }
    }
    dpr[n][m]=dpd[n][m]=dprs[n][m]=dpds[n][m]=1;
    for(int i=n;i;i--){
        for(int j=m;j;j--){
            if(i==n&&j==m) continue; // 特判掉初始状态
            // 所有公式都有记得取模哦
            // dp
            dpr[i][j]=mathmod(dpds[i][j+1]-dpds[i][m-rs[i][j+1]+1],MOD);
            dpd[i][j]=mathmod(dprs[i+1][j]-dprs[n-ds[i+1][j]+1][j],MOD);
            // 前缀和优化
            dprs[i][j]=mathmod(dprs[i+1][j]+dpr[i][j],MOD);
            dpds[i][j]=mathmod(dpds[i][j+1]+dpd[i][j],MOD);
        }
    }
    printf("%lld",mathmod(dpr[1][1]+dpd[1][1],MOD));
    return 0;
}

标签:dpr,rs,题解,转移,dpd,Push,石头,CF1225E,define
From: https://www.cnblogs.com/godmoo/p/18496225

相关文章

  • 题解:P11215 【MX-J8-T3】水星湖
    依旧是模拟赛赛题。HintAnalysis首先你注意到两棵相邻的树是一定不会死的,所以可能会死的只有自己种下去的树,队列维护。接着考虑对于每个位置,\(\text{bfs}\)维护一个最小的长出树的时间\(vis[i][j]\),最后暴力统计答案即可。具体细节看注释。Code#include<bits/stdc++.h>......
  • CRC32爆破脚本 + [MoeCTF 2022]cccrrc 题解
    CRC32爆破原理介绍:CRC(循环冗余校验)是一种用于检测数据传输错误的技术。CRC算法生成一个校验值(校验和),这个值可以附加到数据后面,在数据接收方重新计算校验值并与附加的校验值进行比较,以此来确定数据是否在传输过程中发生了错误CRC32是一种常用的CRC算法,它的校验值长度固定为3......
  • P7910 [CSP-J 2021] 插入排序 题解
    正解首先要注意$2$点:修改数组元素的值会影响接下来的操作.对数组进行排序不会影响接下来的操作.思路直接扫一遍数组.假设排序后$a_x$会在第$p$位上.将$p$初始化为$n$.然后就开始找$x$前后有多少个小于$a_x$的值就行了.时间复杂度:$\Theta(nq)$.注意......
  • P7911 [CSP-J 2021] 网络连接 题解
    模拟代码#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intn,p=1,ans[1003];//没事干的ans数组structnode{ stringop,ad;}a[1003];intws(intn){//位数 intsum=0; if(n==0)return1; while(n){ n......
  • P8816 [CSP-J 2022] 上升点列 题解
    最长上升子序列根据题目中,每个坐标的横纵坐标均单调递增,所以明显可以使用最长上升子序列.定义状态$f_{i,p}$,表示正在节点$i$时,还剩下$p$次插入机会,所能达到的最大长度.定义变量$dis=|x_i-x_j|+|y_i-y_j|-1.$,表示$i$到$j$节点至少要插$dis$个节点.为什么要$-1$......
  • ARC165F题解
    前言\(2024.10.19\)日校测\(T4\),思维太庙,被薄纱了,遂哭弱,写题解以记之。简要题意给你一个长度为\(2n\)的序列\(A,\foralla_i\in[1,n]\),其中\(1\)到\(n\)每个数都出现了两次,现在需要把相同的两个数排到一起,每次操作只能交换相邻两个数,在保证操作次数最小的情况下求出现......
  • P8814 [CSP-J 2022] 解密 题解
    解方程$题目中说,n=pq,ed=(p-1)(q-1)+1,m=n-ed+2.$$把ed的式子展开,得到:$$ed=p(q-1)-(q-1)+1$$ed=pq-p-q+2$$再把展开后的式子带入m中,得:$$m=n-(pq-p-q+2)+2.$$m=n-pq+p+q-2+2$$\becausen=pq$$\thereforem=pq-pq+p+q-2+2$$m=p+q.$$如果想要求出p和q的值,那么可以再......
  • P8815 [CSP-J 2022] 逻辑表达式 题解
    短路我们可以使用一个变量来记录当前有没有短路.设变量短路为$dl$.当$dl$为$0$时,说明当前值为$0$,且运算符为&.当$dl$为$1$时,说明当前值为$1$,且运算符为|.代码重点讲完了,细节可以看代码以及注释.#include<iostream>#include<cstdio>#include<cstring>using......
  • 最佳序列 题解
    最佳序列题解题目描述你得到了一个\(N\)个非负整数组成的序列\(A\)。我们称由序列\(A\)的连续若干项组成的新序列为\(A\)的一个连续子序列。给出两个正整数\(L,R(L\leR)\)。称\(A\)的每一个长度不小于\(L\)且不大于\(R\)的连续子序列为一个纯洁序列,定义纯洁度......
  • 题解 [NOIP2022] 建造军营
    树形\(dp\)好题。观察题目发现,如果B国袭击后,导致A国两个军营不联通,那么B国袭击的一定是一条割边,反之,如果袭击的不是割边,那么不会导致任何影响。所以先进行边双缩点,变成一棵树,记每个联通块(缩完后)内的点数为\(wa\),边数为\(wb\),不妨先考虑对于树的情况如何处理。将问题进行转......