当前位置: 代码迷 >> 综合 >> 牛客第二场 E MAZE —— 线段树 + 矩阵
  详细解决方案

牛客第二场 E MAZE —— 线段树 + 矩阵

热度:17   发布时间:2024-01-09 10:59:20.0

题目链接:点我啊╭(╯^╰)╮

题目大意:

    一张 n × m n×m n×m 的图, 0 0 0 表示可走, 1 1 1 不可走
    只能向下、左右走,不能回走
    多次查询,两种操作:
    将某个位置反转
    问从第一行 a i a_i ai? 到第 n n n b i b_i bi? 的的方案数

解题思路:

     d p [ i ] [ j ] = s u m ( d p [ i ? 1 ] [ k ] dp[i][j] = sum(dp[i-1][k] dp[i][j]=sum(dp[i?1][k] for ( k < j (k < j (k<j and b i k = b i k + 1 = . . . = b i j = 0 ) ) + b_{ik}=b_{ik+1}=...=b_{ij}=0))+ bik?=bik+1?=...=bij?=0))+
                        s u m ( d p [ i ? 1 ] [ k ] sum(dp[i-1][k] sum(dp[i?1][k] for ( k > j (k > j (k>j and b i k = b i k ? 1 = . . . = b i j = 0 ) ) b_{ik}=b_{ik-1}=...=b_{ij}=0)) bik?=bik?1?=...=bij?=0))

    所以相邻两行就可以用矩阵相乘计算
    然后用线段树维护
    每个节点表示一段区间的系数转移矩阵
    时间复杂度: O ( q m 3 l o g n ) O(qm^3logn) O(qm3logn)
    详细可看:这里

核心:线段树维护系数矩阵

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 5e4 + 5;
int n, m, q, op;
int b[maxn][15];
struct node{ll s[15][15];void init() {memset(s, 0, sizeof(s));}node operator + (const node &a) const {node ret; ret.init();for(int i=1; i<=m; i++)for(int j=1; j<=m; j++)for(int k=1; k<=m; k++)ret.s[i][j] = (ret.s[i][j]+s[i][k]*a.s[k][j]%mod) % mod;return ret;}
} t[maxn<<2];  void get(node &h, int r){h.init();for(int i=1; i<=m; i++)if(!b[r][i]){h.s[i][i] = 1;for(int j=i-1; j && !b[r][j]; j--) h.s[j][i] = 1;for(int j=i+1; j<=m && !b[r][j]; j++) h.s[j][i] = 1;}
}void build(int l, int r, int rt){if(l == r){get(t[rt], l);return;}int m = l + r >> 1;build(l, m, rt<<1);build(m+1, r, rt<<1|1);t[rt] = t[rt<<1] + t[rt<<1|1];
}
void update(int pos, int l, int r, int rt){if(l>pos || r<pos) return;if(l == r){get(t[rt], l);return;}int m = l + r >> 1;update(pos, l, m, rt<<1);update(pos, m+1, r, rt<<1|1);t[rt] = t[rt<<1] + t[rt<<1|1];
}
int main() {scanf("%d%d%d", &n, &m, &q);for(int i=1; i<=n; i++){char s[15];scanf("%s", s+1);for(int j=1; j<=m; j++)if(s[j]=='1') b[i][j] = 1;}build(1, n, 1);while(q--){int u, v;scanf("%d%d%d", &op, &u, &v);if(op & 1) b[u][v] ^= 1, update(u, 1, n, 1);else printf("%d\n", t[1].s[u][v]);}
}