2019牛客多校第二场E MAZE(线段树 + 矩阵)题解
题意:
n * m的矩阵,为0表示可以走,1不可以走。规定每走一步只能向下、向左、向右走。现给定两种操作:
一.1 x y表示翻转坐标(x,y)的0、1。
二.2 x y表示从(1,x)走到(n,y)有几种走法
思路:
假设\(dp[i][j]\)表示从下一层能到达(i,j)点的路径数,那么显然到达(i,j)的路径数为\(dp[i + 1][j]\)。
我们能很显然的得到转移方程\(dp[i][j] = \sum_{k = l}^r dp[i - 1][k]\),其中l~r为(i,j)下方能直接走到(i,j)的连续区间。
我们可以直接用矩阵维护这个转移方程:
\begin{matrix}
dp[i][1] & dp[i][2] & dp[i][3] & \cdots & dp[i][m]
\end{matrix}
\right)
*
A_i=
\left(
\begin{matrix}
dp[i + 1][1] & dp[i + 1][2] & dp[i + 1][3] & \cdots & dp[i + 1][m]
\end{matrix}
\right)
\]
然后用线段树维护矩阵乘积即可
从(1,x)走到(n,y)只需把x位置置为1,然后乘以\(\prod_{i = 1}^n A_i\)
代码:
#include<cstdio>
#include<set>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 50000 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int n, m, q;
int mp[maxn][12];
char s[12];
struct Mat{
ll s[12][12];
void init_zero(){
for(int i = 0; i < 12; i++)
for(int j = 0; j < 12; j++)
s[i][j] = 0;
}
};
Mat pmul(Mat a, Mat b, int len){
Mat c;
c.init_zero();
for(int i = 1; i <= len; i++){
for(int j = 1; j <= len; j++){
for(int k = 1; k <= len; k++){
c.s[i][j] = (c.s[i][j] + a.s[i][k] * b.s[k][j]) % MOD;
}
}
}
return c;
}
Mat mul[maxn << 2], a[maxn];
void pushup(int rt){
mul[rt] = pmul(mul[rt << 1], mul[rt << 1 | 1], m);
}
void build(int l, int r, int rt){
if(l == r){
for(int i = 1; i <= m; i++)
for(int j = 1; j <= m; j++)
mul[rt].s[i][j] = a[l].s[i][j];
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int pos, int l, int r, Mat aa, int rt){
if(l == r){
for(int i = 1; i <= m; i++)
for(int j = 1; j <= m; j++)
mul[rt].s[i][j] = aa.s[i][j];
return;
}
int m = (l + r) >> 1;
if(pos <= m)
update(pos, l, m, aa, rt << 1);
else
update(pos, m + 1, r, aa, rt << 1 | 1);
pushup(rt);
}
int main(){
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; i++){
scanf("%s", s + 1);
for(int j = 1; j <= m; j++){
mp[i][j] = s[j] - '0';
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
int base;
base = 1;
for(int k = j; k >= 1; k--){
if(mp[i][k] == 1) base = 0;
a[i].s[k][j] = base;
}
base = 1;
for(int k = j; k <= m; k++){
if(mp[i][k] == 1) base = 0;
a[i].s[k][j] = base;
}
}
}
// for(int k = 1; k <= n; k++){
// for(int i = 1; i <= m; i++){
// for(int j = 1; j <= m; j++){
// printf("%d ", a[k].s[i][j]);
// }
// puts("");
// }
// puts("*****");
// }
build(1, n, 1);
while(q--){
int ques, i, j;
scanf("%d", &ques);
scanf("%d%d", &i, &j);
if(ques == 1){
mp[i][j] = !mp[i][j];
for(int j = 1; j <= m; j++){
int base;
base = 1;
for(int k = j; k >= 1; k--){
if(mp[i][k] == 1) base = 0;
a[i].s[k][j] = base;
}
base = 1;
for(int k = j; k <= m; k++){
if(mp[i][k] == 1) base = 0;
a[i].s[k][j] = base;
}
}
update(i, 1, n, a[i], 1);
}
else{
Mat ret;
ret.init_zero();
ret.s[1][i] = 1;
ret = pmul(ret, mul[1], m);
printf("%lld\n", ret.s[1][j]);
}
}
return 0;
}
/*
2 6 1
0 0 0 1 0 0
1 0 1 0 1 0
*/
2019牛客多校第二场E MAZE(线段树 + 矩阵)题解的更多相关文章
- MAZE(2019年牛客多校第二场E题+线段树+矩阵乘法)
题目链接 传送门 题意 在一张\(n\times m\)的矩阵里面,你每次可以往左右和下三个方向移动(不能回到上一次所在的格子),\(1\)表示这个位置是墙,\(0\)为空地. 现在有\(q\)次操作 ...
- [2019牛客多校第二场][E. MAZE]
题目链接:https://ac.nowcoder.com/acm/contest/882/E 题目大意:有一个\(n\times m\)的01矩阵,一开始可以从第一行的一个点出发,每次可以向左.向右. ...
- 2019牛客多校第二场 A Eddy Walker(概率推公式)
2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...
- 2019牛客多校第一场E ABBA(DP)题解
链接:https://ac.nowcoder.com/acm/contest/881/E 来源:牛客网 ABBA 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语 ...
- 2019牛客多校第二场H-Second Large Rectangle
Second Large Rectangle 题目传送门 解题思路 先求出每个点上的高,再利用单调栈分别求出每个点左右两边第一个高小于自己的位置,从而而得出最后一个大于等于自己的位置,进而求出自己的位 ...
- [2019牛客多校第二场][G. Polygons]
题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...
- 2019 牛客多校第二场 H Second Large Rectangle
题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目大意 给定一个 n * m 的 01 矩阵,求其中第二大的子矩阵,子矩阵元素必须全部为 1.输出其大小 ...
- 2019牛客多校第二场H题(悬线法)
把以前的题补补,用悬线求面积第二大的子矩形.我们先求出最大子矩阵的面积,并记录其行三个方向上的悬线长度.然后排除这个矩形,记得还得特判少一行或者少一列的情况 #include <bits/std ...
- 2019牛客多校第二场D-Kth Minimum Clique
Kth Minimum Clique 题目传送门 解题思路 我们可以从没有点开始,把点一个一个放进去,先把放入一个点的情况都存进按照权值排序的优先队列,每次在新出队的集合里增加一个新的点,为了避免重复 ...
随机推荐
- 使用fdopen对python进程产生的文件进行权限最小化配置
需求背景 用python进行文件的创建和读写操作时,我们很少关注所创建的文件的权限配置.对于一些安全性较高的系统,如果我们创建的文件权限其他用户或者同一用户组里的其他用户有可读权限的话,有可能导致不必 ...
- uni-app开发经验分享八: 实现微信APP支付的全过程详解
背景 最近项目使用uni-app实现微信支付,把过程简单记录下,帮助那些刚刚基础uni-app,苦于文档的同学们.整体来说实现过程和非uni-app的实现方式没有太大不同,难点就在于uni-app对于 ...
- java虚拟机入门(二)-探索内存世界
上节简单介绍了一下jvm的内存布局以及简单概念,那么对于虚拟机来说,它是怎么一步步的让我们能执行方法的呢: 1.首先,jvm启动时,跟个小领导一样会根据配置参数(没有配置的话jvm会有默认值)向大领导 ...
- Zerotier在windows下实现内网远程桌面
Zerotier实现内网远程桌面 使用背景 实验室设备条件过于恶劣 向日葵在有些场景下会莫名崩溃,或者画面不动. Teamviewer免费版在之前用的时候出现过疑似商业行为被断连,github上寻解决 ...
- websocket心跳重连 websocket-heartbeat-js
初探和实现websocket心跳重连(npm: websocket-heartbeat-js) 心跳重连缘由 websocket是前后端交互的长连接,前后端也都可能因为一些情况导致连接失效并且相互之间 ...
- 解决windows git乱码问题
在windows中打开git bash git config --global i18n.commitencoding utf-8 设置提交日志使用utf-8 git config --g ...
- java.lang.IllegalStateException Unable to find a @SpringBootConfiguration错误解决方案
问题描述:java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @Co ...
- 系列trick - 建图
对偶图 主体思想:平面图的割,等价于对偶图的路 例题:[BeiJing2006]狼抓兔子 网上有114514篇题解,这里不赘述 点变边 主体思想:点带点权,而要在点上实现一些在边上的问题,比如最小割点 ...
- 基于粒子群算法的分组背包MATLAB实现
抽空看了一段时间的粒子群算法,这里仅针对其应用于动态规划中的背包问题的情况做下总结归纳,其他应用可以之后想到了再添加. 一:分组背包问题简介 假设有3个组,每组有2个物品,每种物品有3种属性,价值.体 ...
- sql多行合并
例一 SELECT qqo.questionID '题目id', qqo.quesOption '选项' FROM qz_question_option qqo, qz_question qq WHE ...