题目链接:https://ac.nowcoder.com/acm/contest/882/E

题目大意:有一个\(n\times m\)的01矩阵,一开始可以从第一行的一个点出发,每次可以向左、向右、向下移动一格且不能回头。中途会有一些点变为障碍物(用1表示),或者从障碍物变回可以通过的格子,同时还需要处理询问:从\((1,a)\)出发,走到\((n,b)\)的方案数有多少种。\(n\leq 50000,\ m\leq 10\)

题解:设\(f(i,j)\)为走到\((i,j)\)的方案数,且第\(i\)行里包含点\((i,j)\)的区间为\([l,r]\),则有\(f(i,j)=\sum_{k=l}^{r}f(i-1,k)\),这里的\(k\)就代表着从前一行的第\(k\)列走下来。可以发现这个转移方程可以转换成一个矩阵形式,即\((f(i,1),f(i,2),...,f(i,m))=(f(i-1,1),f(i-1,2),...,f(i-1,m))\cdot A\)其中\(A\)为状态转移矩阵。求从第\(i-1\)行到第\(i\)行的转移矩阵是可以用\(O(m^2)\)的时间复杂度来实现的。而最后一行的答案就是第一行的状态矩阵乘上这\(n\)行转移矩阵的乘积。在本题中,由于给出了起点和终点,所以若设这\(n\)行转移矩阵的乘积为\(A\),则答案就是\(A(a,b)\)。用线段树维护每行的矩阵以及区间的矩阵乘积即可。

 #include<bits/stdc++.h>
using namespace std;
#define N 50001
#define LL long long
#define MOD 1000000007
LL n,m,q,op,x,y,a[N][];
struct Matrix
{
LL n,m;
LL f[][];
void init(LL nn,LL mm)
{
n=nn,m=mm;
for(LL i=;i<=n;i++)
for(LL j=;j<=m;j++)
f[i][j]=;
}
void set_E(LL nn)
{
n=m=nn;
for(LL i=;i<=n;i++)
for(LL j=;j<=n;j++)
f[i][j]=i==j;
}
Matrix operator *(const Matrix &t)const
{
Matrix res;
res.init(n,t.m);
for(LL i=;i<=n;i++)
for(LL j=;j<=t.m;j++)
for(LL k=;k<=m;k++)
(res.f[i][j]+=f[i][k]*t.f[k][j]%MOD)%=MOD;
return res;
}
void get(LL i,LL mm)
{
init(mm,mm);
LL l=,r=;
for(LL j=;j<=m;j++)
{
if(a[i][j]==)
{
l=r=j+;
continue;
}
while(r<=m && a[i][r]==a[i][l])r++;r--;
for(LL k=l;k<=r;k++)
f[k][j]++;
}
}
};
struct Segment_Tree
{
struct rua
{
LL l,r;
Matrix v;
}t[N<<];
void Update(LL x)
{
t[x].v=t[x*].v*t[x*+].v;
}
void Build(LL l,LL r,LL x)
{
t[x].l=l,t[x].r=r;
if(l==r)
{
t[x].v.get(l,m);
return;
}
LL mid=l+r>>;
Build(l,mid,x*);
Build(mid+,r,x*+);
Update(x);
}
void Change(LL x,LL y)
{
LL l=t[x].l,r=t[x].r;
LL mid=l+r>>;
if(l==y && y==r)
{
t[x].v.get(y,m);
return;
}
if(y<=mid)Change(x*,y);
else Change(x*+,y);
Update(x);
}
Matrix Query(LL L,LL R,LL x)
{
LL l=t[x].l,r=t[x].r;
LL mid=l+r>>;
if(L<=l && r<=R)return t[x].v;
Matrix res;
res.set_E(m);
if(L<=mid)res=res*Query(L,R,x*);
if(R>mid)res=res*Query(L,R,x*+);
return res;
}
}T;
LL get()
{
char ch=getchar();
while(ch!='' && ch!='')
ch=getchar();
return ch-'';
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&q);
for(LL i=;i<=n;i++)
for(LL j=;j<=m;j++)
a[i][j]=get();
T.Build(,n,);
while(q--)
{
scanf("%lld%lld%lld",&op,&x,&y);
if(op==)
{
a[x][y]^=;
T.Change(,x);
}
if(op==)
{
Matrix tmp=T.Query(,n,);
printf("%lld\n",tmp.f[x][y]);
}
}
return ;
}

[2019牛客多校第二场][E. MAZE]的更多相关文章

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

    题意: n * m的矩阵,为0表示可以走,1不可以走.规定每走一步只能向下.向左.向右走.现给定两种操作: 一.1 x y表示翻转坐标(x,y)的0.1. 二.2 x y表示从(1,x)走到(n,y) ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. 2019牛客多校第二场F-Partition problem(搜索+剪枝)

    Partition problem 题目传送门 解题思路 假设当前两队的对抗值为s,如果把红队中的一个人a分配到白队,s+= a对红队中所有人的对抗值,s-= a对白队中所有人的对抗值.所以我们可以先 ...

  9. 2019牛客多校第二场BEddy Walker 2——BM递推

    题意 从数字 $0$ 除法,每次向前走 $i$ 步,$i$ 是 $1 \sim K$ 中等概率随机的一个数,也就是说概率都是 $\frac{1}{K}$.求落在过数字 $N$ 额概率,$N=-1$ 表 ...

随机推荐

  1. 拯救你丢失的精度——BigInteger和BigDecimal类(入门)

    第三阶段 JAVA常见对象的学习 BigInteger和BigDecimal类 BigInteger类 (一) 构造方法: //针对超过整数范围的运算(整数最大值:2147483647) BigInt ...

  2. 使用mybatis出现异常:invalid comparison: java.time.LocalDateTime and java.lang.String

    整了半天终于找到问题所在:在mapper文件中,对该参数进行了和字符串的对比,如下: <if test="startTime != null and startTime != '' a ...

  3. 大数据学习笔记【一】:Hadoop-3.1.2完全分布式环境搭建(Windows 10)

    一.前言 Hadoop原理架构本人就不在此赘述了,可以自行百度,本文仅介绍Hadoop-3.1.2完全分布式环境搭建(本人使用三个虚拟机搭建). 首先,步骤: ① 准备安装包和工具: hadoop-3 ...

  4. SSM框架的整合与使用——实现简单的转账系统

    一.整合思路 SSM框架即SpringMVC + Spring + MyBati框架集,是一种轻量级的Web开源框架.它们各自在JAVA三层架构中负责的模块如下图所示: 其中,SpringMVC与Sp ...

  5. 欢迎使用f MWeb

    MWeb 是专业的 Markdown 写作.记笔记.静态博客生成软件,目前已支持 Mac,iPad 和 iPhone.MWeb 有以下特色: 软件本身: 使用原生的 macOS 技术打造,追求与系统的 ...

  6. Prometheus Operator 的安装

    Prometheus Operator 的安装 接下来我们用自定义的方式来对 Kubernetes 集群进行监控,但是还是有一些缺陷,比如 Prometheus.AlertManager 这些组件服务 ...

  7. 手动部署k8s-prometheus

    简介 Prometheus 最初是 SoundCloud 构建的开源系统监控和报警工具,是一个独立的开源项目,于2016年加入了 CNCF 基金会,作为继 Kubernetes 之后的第二个托管项目. ...

  8. linux mysql 数据库操作导入导出 数据表导出导入

    linux mysql 数据库操作导入导出 数据表导出导入 1,数据库导入 mysql -uroot -p show databases; create database newdb; use 数据库 ...

  9. TCP协议探究(三):RTT、滑动窗口和阻塞处理

    1 RTT算法 1.1 概述 上一节说了重传机制需要设置一个重传超时值(RTO,Retransmission TimeOut),RTO设长了,重发太慢:设短了,可能导致包没有丢,就重发了,可能导致雪崩 ...

  10. shake.js实现微信摇一摇功能

    项目要求实现点击摇一摇图片,图片摇一摇,并且摇一摇手机,图片也要摇一摇. 关于用js怎样实现摇一摇手机图片摇一摇,我在网络上找了一些方法,真正有用的是shake.js. 接下来,上shake.js源码 ...