题目链接: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. Date、DateFormat和Calendar类的简单认识

    第三阶段 JAVA常见对象的学习 Date.DateFormat和Calendar类的简单认识 Date类 Date:表示特定的瞬间,精确到毫秒. (一) 构造方法: Date():根据当前的默认毫秒 ...

  2. split(".")不生效的问题

    前言:今天用String的split(".")函数分割字符串,结果总是一个空的String数组: 解决:输入的regex是一个正则表达式,很多在正则表达式里面有特殊意义的比如 &q ...

  3. Timezone offset does not match system offset: 0 != -32400. Please, check your config files

    apscheduler使用uWSGI的mule模块部署的时候报错, 因为系统时区和代码运行时区不一样导致. 解决办法:在初始化的时候指定上海的时区 scheduler = BlockingSchedu ...

  4. 第八章 ZYNQ-MIZ701 软硬调试高级技巧

      软件和硬件的完美结合才是SOC的优势和长处,那么开发ZYNQ就需要掌握软件和硬件开发的调试技巧,这样才能同时分析软件或者硬件的运行情况,找到问题,最终解决.那么本章将通过一个简单的例子带大家使用v ...

  5. Thread 和 Runnable

    Thread 和 Runnable 1. 简介 Java 主要是通过 java.lang.Thread 类以及 java.lang.Runnable 接口实现线程机制的. Thread 类为底层操作系 ...

  6. 复习最短路 spfa+dijstra堆优化

    题目很简单,, 但是wa了三次,, 用<vector>之前一定要记得clear()...简单说下 spfa的问题 和bell_forman有点类似 每次取出一个点 然后更新 并把更新了的节 ...

  7. 6-MySQL DBA笔记-查询优化

    第6章 查询优化 查询优化是研发人员比较关注也是疑问较多的领域.本章首先为读者介绍常用的优化策略.MySQL的优化器.连接机制,然后介绍各种语句的优化,在阅读本章之前,需要先对EXPLAIN命令,索引 ...

  8. Linux下mysql创建用户并设置权限,设置远程连接

    为了安全考虑,OneinStack仅允许云主机本机(localhost)连接数据库,如果需要远程连接数据库,需要如下操作:打开iptables 3306端口 # iptables -I INPUT 4 ...

  9. 维护solr索引库

    一 2)solrcore    一个solr下可以有多个solrcore,每个solrcore就是一个独立的索引库3)solrconfig.xml    lib:配置solr的扩展包的位置,不指定路径 ...

  10. JS基础_函数的简介

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...