题意

给一个\(n\times m\)的01矩阵,1代表有墙,否则没有,每一步可以从\(b[i][j]\)走到\(b[i+1][j]\),\(b[i][j-1]\),\(b[i][j+1]\),有两种询问:

  • \(q=1\),将\(b[x][y]\)的状态反转
  • \(q=2\),计算从\(b[1][x]\)走到\(b[n][y]\)的方案数

分析

先不考虑状态反转的情况,设\(dp[i][j]\)为从第\(i-1\)层经过\(b[i-1][j]\)到达\(b[i][j]\)的方案数

\[dp[i][j]=sum(dp[i-1][k]~for~(k<j~and~b[i-1][k]=b[i-1][k+1]=\dots=b[i-1][j]=0))\\
+sum(dp[i-1][k]~for~(k>j~and~b[i-1][k]=b[i-1][k-1]=\dots=b[i-1][j]=0))
\]

\(dp[i][j]\)等于\(b[i-1][j]\)向左和向右\(b[i-1][k]\)都等于0的那些\(dp[i-1][k]\)的和

0 0 0 1 0 0
1 0 1 0 1 0

例如当n=2,m=6时

\(dp[2][2]=dp[1][1]+dp[1][2]+dp[1][3]\)

\(dp[2][6]=dp[1][5]+dp[1][6]\)

第\(i\)行的dp值到第\(i+1\)行的dp值的转移可以用矩阵\(Mi\)实现

用上图的例子,从第1行转移到第2行

\[\left [ \begin{matrix}dp[1][1]\\dp[1][2]\\dp[1][3]\\dp[1][4]\\dp[1][5]\\dp[1][6]\end{matrix}\right ] \times
\left [ \begin{matrix}1&1&1&0&0&0\\1&1&1&0&0&0\\1&1&1&0&0&0\\0&0&0&0&0&0\\
0&0&0&0&1&1\\0&0&0&0&1&1\end{matrix}\right ]
=\left [ \begin{matrix}dp[2][1]\\dp[2][2]\\dp[2][3]\\dp[2][4]\\dp[2][5]\\dp[2][6]\end{matrix}\right ]
\]

求从\(b[1][x]\)走到\(b[n][y]\)的方案数,即令\(dp[1][x]=1\),求\(dp[n+1][y]\)。

若令\(ans=M_1\times M_2 \times M_3\times \dots \times M_n\)

则答案为\(ans[x][y]\)

用线段树维护\(M_1\dots M_n\),反转\(b[x][y]\)操作就变成了单点修改,问题就完美解决了

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=5e4+10;
int n,m,q;
char b[maxn][11];
int a[maxn][11];
struct node{
ll a[11][11];
node operator *(const node &r) const{
node res;
memset(res.a,0,sizeof(res.a));
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
for(int k=1;k<=m;k++){
res.a[i][j]=(res.a[i][j]+a[i][k]*r.a[k][j]%mod)%mod;
}
}
}
return res;
}
}tr[maxn<<2];
void pp(int p){
tr[p]=tr[p<<1]*tr[p<<1|1];
}
void cal(int p,int l){
memset(tr[p].a,0,sizeof(tr[p].a));
for(int i=1;i<=m;i++){
int pos=i;
while(pos<=m&&!a[l][pos]){
tr[p].a[i][pos]=1;
pos++;
}
pos=i;
while(pos>=1&&!a[l][pos]){
tr[p].a[i][pos]=1;
pos--;
}
}
}
void bd(int l,int r,int p){
if(l==r){
cal(p,l);
return;
}int mid=l+r>>1;
bd(lson);bd(rson);
pp(p);
}
void up(int x,int l,int r,int p){
if(l==r){
cal(p,l);
return;
}int mid=l+r>>1;
if(x<=mid) up(x,lson);
else up(x,rson);
pp(p);
}
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++){
scanf("%s",b[i]+1);
for(int j=1;j<=m;j++){
a[i][j]=(b[i][j]-'0');
}
}
bd(1,n,1);
while(q--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==1){
a[x][y]^=1;
up(x,1,n,1);
}else{
printf("%lld\n",tr[1].a[x][y]);
}
}
return 0;
}

2019牛客暑期多校训练营(第二场)E 线段树维护dp转移矩阵的更多相关文章

  1. 2019牛客暑期多校训练营(第二场) H-Second Large Rectangle(单调栈)

    题意:给出由01组成的矩阵,求求全是1的次大子矩阵. 思路: 单调栈 全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如: 1 0 0 1 ...

  2. 2020牛客暑期多校训练营 第二场 K Keyboard Free 积分 期望 数学

    LINK:Keyboard Free 我要是会正经的做法 就有鬼了. 我的数学水平没那么高. 三个同心圆 三个动点 求围成三角形面积的期望. 不会告辞. 其实可以\(n^2\)枚举角度然后算出面积 近 ...

  3. 2020牛客暑期多校训练营 第二场 J Just Shuffle 置换 群论

    LINK:Just Shuffle 比较怂群论 因为没怎么学过 置换也是刚理解. 这道题是 已知一个置换\(A\)求一个置换P 两个置换的关键为\(P^k=A\) 且k是一个大质数. 做法是李指导教我 ...

  4. 2020牛客暑期多校训练营 第二场 I Interval 最大流 最小割 平面图对偶图转最短路

    LINK:Interval 赛时连题目都没看. 观察n的范围不大不小 而且建图明显 考虑跑最大流最小割. 图有点稠密dinic不太行. 一个常见的trick就是对偶图转最短路. 建图有点复杂 不过建完 ...

  5. 2020牛客暑期多校训练营 第二场 C Cover the Tree 构造 贪心

    LINK:Cover the Tree 最受挫的是这道题,以为很简单 当时什么都想不清楚. 先胡了一个树的直径乱搞的贪心 一直过不去.后来意识到这类似于最经典长链剖分优化贪心的做法 然后那个是求最大值 ...

  6. 2020牛客暑期多校训练营 第二场 B Boundary 计算几何 圆 已知三点求圆心

    LINK:Boundary 计算几何确实是弱项 因为好多东西都不太会求 没有到很精通的地步. 做法很多,先说官方题解 其实就是枚举一个点 P 然后可以发现 再枚举一个点 然后再判断有多少个点在圆上显然 ...

  7. 2020牛客暑期多校训练营 第二场 A All with Pairs 字符串hash KMP

    LINK:All with Pairs 那天下午打这个东西的时候状态极差 推这个东西都推了1个多小时 (比赛是中午考试的我很困 没睡觉直接开肝果然不爽 一开始看错匹配的位置了 以为是\(1-l\)和\ ...

  8. 2019牛客暑期多校训练营(第九场) D Knapsack Cryptosystem

    题目 题意: 给你n(最大36)个数,让你从这n个数里面找出来一些数,使这些数的和等于s(题目输入),用到的数输出1,没有用到的数输出0 例如:3  4 2 3 4 输出:0 0 1 题解: 认真想一 ...

  9. 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题)

    layout: post title: 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题) author: "luowentaoaa" c ...

  10. [暴力+前缀和]2019牛客暑期多校训练营(第六场)Upgrading Technology

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

随机推荐

  1. GTID复制

    什么是GTID呢, 简而言之,就是全局事务ID(global transaction identifier ),最初由google实现,官方MySQL在5.6才加入该功能.GTID是事务提交时创建分配 ...

  2. Linux命令-文件管理篇-cat

    1.cat 说明 cat 是一个文本文件查看和连接工具.查看一个文件的内容,用cat比较简单,就是cat 后面直接接文件名. 2.使用权限 所有使用者 <!-- more --> 3.ca ...

  3. 【原创】大叔经验分享(59)kudu查看table size

    kudu并没有命令可以直接查看每个table占用的空间,可以从cloudera manager上间接查看 CM is scrapping and aggregating the /metrics pa ...

  4. HTTP缓存总结

    在具体了解 HTTP 缓存之前先来明确几个术语:1.缓存命中率:从缓存中得到数据的请求数与所有请求数的比率.理想状态是越高越好.2.过期内容:超过设置的有效时间,被标记为“陈旧”的内容.通常过期内容不 ...

  5. (三)创建基于maven的javaFX+springboot项目创建

    创建基于maven的javaFx+springboot项目有两种方式,第一种为通过非编码的方式来设计UI集成springboot:第二种为分离用户界面(UI)和后端逻辑集成springboot,其中用 ...

  6. 使用 “Unicode 字符集 ” 使用错误,应该使用 “使用多字节字符集”

    “void ATL::CStringT<BaseType,StringTraits>::Format(const wchar_t *,...)”: 不能将参数 1 从“const char ...

  7. 记项目管理大作业Web项目Mandrian的全流程[其一] 整体分析: 功能划分, 组织结构

    Mandrian是个图书管理系统, 具体需求老师给出 这个项目的目的主要是管理过程和高层设计的学习和实践 11人小组, 路人局 成员调查 这里由于很多人我都不认识, 所以我提前发了一个能力调查表, 调 ...

  8. ASP.NET数据库连接类(SqlDBHelper)

    第一步:创建一个名为SqlDBHelper的类,用来作为联通数据库和系统之间的桥梁. 第二步:引入命名空间,如果System.Configuration.System.Transcations这两个命 ...

  9. array数据处理

    之前写过map,forEach,现在用到every和some,记录一下当作学习笔记,方便以后翻阅. forEach是没有返回值的,对原数组进行修改: // forEach没有返回值,只针对每个元素调用 ...

  10. maven中如何将所有引用的jar包打包到一个jar中

    在pom文件的build节点中添加这个插件的引用: <plugins> <plugin> <artifactId>maven-assembly-plugin< ...