题意:

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)的连续区间。

我们可以直接用矩阵维护这个转移方程:

\[\left(
\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(线段树 + 矩阵)题解的更多相关文章

  1. MAZE(2019年牛客多校第二场E题+线段树+矩阵乘法)

    题目链接 传送门 题意 在一张\(n\times m\)的矩阵里面,你每次可以往左右和下三个方向移动(不能回到上一次所在的格子),\(1\)表示这个位置是墙,\(0\)为空地. 现在有\(q\)次操作 ...

  2. [2019牛客多校第二场][E. MAZE]

    题目链接:https://ac.nowcoder.com/acm/contest/882/E 题目大意:有一个\(n\times m\)的01矩阵,一开始可以从第一行的一个点出发,每次可以向左.向右. ...

  3. 2019牛客多校第二场 A Eddy Walker(概率推公式)

    2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...

  4. 2019牛客多校第一场E ABBA(DP)题解

    链接:https://ac.nowcoder.com/acm/contest/881/E 来源:牛客网 ABBA 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语 ...

  5. 2019牛客多校第二场H-Second Large Rectangle

    Second Large Rectangle 题目传送门 解题思路 先求出每个点上的高,再利用单调栈分别求出每个点左右两边第一个高小于自己的位置,从而而得出最后一个大于等于自己的位置,进而求出自己的位 ...

  6. [2019牛客多校第二场][G. Polygons]

    题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...

  7. 2019 牛客多校第二场 H Second Large Rectangle

    题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目大意 给定一个 n * m 的 01 矩阵,求其中第二大的子矩阵,子矩阵元素必须全部为 1.输出其大小 ...

  8. 2019牛客多校第二场H题(悬线法)

    把以前的题补补,用悬线求面积第二大的子矩形.我们先求出最大子矩阵的面积,并记录其行三个方向上的悬线长度.然后排除这个矩形,记得还得特判少一行或者少一列的情况 #include <bits/std ...

  9. 2019牛客多校第二场D-Kth Minimum Clique

    Kth Minimum Clique 题目传送门 解题思路 我们可以从没有点开始,把点一个一个放进去,先把放入一个点的情况都存进按照权值排序的优先队列,每次在新出队的集合里增加一个新的点,为了避免重复 ...

随机推荐

  1. JVM有哪些垃圾回收器

    JVM 的垃圾回收器 目录 JVM 的垃圾回收器 经典垃圾收集器 Serial 收集器 ParNew 收集器 Parallel Scavenge 收集器 Serial Old 收集器 Parallel ...

  2. wordpress迁移报错

    背景: 因为一些原因迁移wordpress的博客.备份好数据库和网站源码到另一台生产环境上线的时候报错: Warning: require(/www/wwwroot/pazzn/wp-includes ...

  3. Centos 7 安装 erlang

    https://www.cnblogs.com/swyy/p/11582309.html https://blog.csdn.net/qq_20492999/article/details/81254 ...

  4. 为什么在使用LESS 除法计算时会出问题

    hello,各位小伙伴们好,最近一直有小伙伴问我为什么写Less的时候,发现除法有了问题,在生成的css文件中,不给我们输出正确结果了. 直接抛结论: LESS 版本升级,EasyLess插件 新版本 ...

  5. PowerBI数据建模时的交叉连接问题

    方案一.在PowerPivot中,将其中一张表复制多份,分别与另一张表做链接. 方案二.在PowerQuery中,做多次合并查询,把所有数据集中在一张表中,方便后面的数据分析. 思考:不仅仅是在Pow ...

  6. 深入理解java虚拟机,GC参考手册

    深入理解java虚拟机 一.<深入理解Java虚拟机> 1.第2章 Java内存区域与内存溢出异常 2.第3章 垃圾收集器与内存分配策略 3.第4章 虚拟机性能监控与故障处理工具 4.第5 ...

  7. FortiGate防火墙办公网常用配置

    1.建立主备机 2.配置端口 3.配置SD-WAN 4.新建上网路由 5.新建上网策略 6.建立与其他点的IPSec VPN或点对点专线

  8. UML——基本结构

    一.宏观导图 学习UML的时候我们首先要把握好她的结构,基本上好料都在里面了.最重要的是构造块的学习. 公共机制:是为了让我们更加清楚的描述UML的各种关系.图.事物等. 规则:和语法的意思差不多,就 ...

  9. DolphinScheduler源码分析之EntityTestUtils类

    1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license ...

  10. Java ArrayList源码分析(含扩容机制等重点问题分析)

    写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...