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 题目传送门 解题思路 我们可以从没有点开始,把点一个一个放进去,先把放入一个点的情况都存进按照权值排序的优先队列,每次在新出队的集合里增加一个新的点,为了避免重复 ...
随机推荐
- Linux Ubuntu系统版本通过Crontab设置定时任务的执行
Linux Ubuntu系统版本通过Crontab设置定时任务的执行 本文由本人收集网络信息总结而来 特别鸣谢:https://linux.zone/2258 1 crontab 简单介绍以及语法使用 ...
- [从源码学设计]蚂蚁金服SOFARegistry之延迟操作
[从源码学设计]蚂蚁金服SOFARegistry之延迟操作 0x00 摘要 SOFARegistry 是蚂蚁金服开源的一个生产级.高时效.高可用的服务注册中心. 本系列文章重点在于分析设计和架构,即利 ...
- 计算机网络安全 —— 对称加密算法 DES
一.对称加密算法概念 我们通过计算机网络传输数据时,如果无法防止他人窃听, 可以利用密码学技术将发送的数据变换成对任何不知道如何做逆变换人都不可理解的形式, 从而保证了数据的机密性.这种变换被称为加密 ...
- 小白都看得懂的Javadoc使用教程
Javadoc是什么 官方回答: Javadoc is a tool for generating API documentation in HTML format from doc comments ...
- code-server scala error: object apache is not a member of package org
原因是scala缺少包,需要把spark或对应的包放入scala目录下的lib,然后重启主机,在terminal输入reboot即可. 如果不重启主机,则在交互式编程中可以成功import.但是直接在 ...
- 京东热 key 探测框架新版发布,单机 QPS 可达 35 万
https://mp.weixin.qq.com/s/3URAvUF6zwxeF5Kkc1aWHA 京东热 key 探测框架新版发布,单机 QPS 可达 35 万 原创 Hollis Hollis 2 ...
- Redis 实战 —— 10. 实现内容搜索、定向广告和职位搜索
使用 Redis 进行搜索 P153 通过改变程序搜索数据的方式,并使用 Redis 来减少绝大部分基于单词或者关键字进行的内容搜索操作的执行时间. P154 基本搜索原理 P154 倒排索引 (in ...
- Docker Desktop启动Kubernetes
Docker_Desktop启动Kubernetes 参考仓库:https://github.com/AliyunContainerService/k8s-for-docker-desktop 视频参 ...
- Redis4.0.1的安装及哨兵模式的配置
https://blog.csdn.net/u014182745/article/details/76294146
- 数据库备份和恢复---MariaDB
定义 数据备份:将源数据再次存储到新的位置 数据恢复:将备份好的数据重新应用到数据库系统 常见的备份类型: 按照是否备份整个数据集来分 完全备份:备份从开始到执行备份这一时刻的所有数据集 增量备份:备 ...