MAZE

牛客多校赛第二场E

dp + 线段树 维护矩阵

大概题意是给出01矩阵,0代表可走1代表不可走,问从(1,x) 到(n,y)有多少走法,为什么要有线段树呢,因为题目给出了一个操作代表可以把(x,y)的状态反过来,0是1,1变为0;

那么要线段树的作用是什么.维护矩阵,矩阵如何得来.

我们知道我们可以从一个点向左右下走,那么 (i + 1,j)这个点有多少个在i行的点可以到呢

假如i行状态为100010 到达 (i+ 1 ,2) 可以由(i ,1)(i , 2)(i ,3)这3个点可以到达 那么是不是就可以知道

dp[i + 1][2] = dp[i][1] + dp[i][2] + dp[i][3] ,对于每个点来说我们都可以这么推出来那么

\bigl(\begin{smallmatrix} dp[i + 1][0], &dp[i +1][1] , &dp[i +1][2] , & dp[i +1][3] , & dp[i +1][4] , & dp[i +1][5] \end{smallmatrix}\bigr) = \bigl(\begin{smallmatrix} dp[i][0], &dp[i][1] , &dp[i][2] , & dp[i][3] , & dp[i][4] , & dp[i][5] \end{smallmatrix}\bigr)*\begin{pmatrix} 0 & 0 & 0 & 0 & 0 & 0\\ 0 & 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 \end{pmatrix}

仔细想一想是不是

所以我们用线段树维护出每一行的状态转移矩阵将每一行的状态转移矩阵乘起来就是从第一行到最后一行的最后的状态,最后输出

A(x,y)这里为什么需要直接输出Ax,y 我还没太想明白 后补把。。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 50000 + 5;
int n,m,q;
struct Mat {
    long long m[15][15];
}tree[N << 2];

Mat operator *(Mat a,Mat b)
{
    Mat c;
    memset(c.m,0,sizeof(c.m));
    for(int k = 0; k < m;k++){
        for(int i = 0; i < m; i++){
            if(a.m[i][k] == 0) continue;
                for(int j = 0; j < m; j++)
                        c.m[i][j] = (c.m[i][j]+a.m[i][k]*b.m[k][j])%1000000007;

        }
    }
    return c;
}
string s[N];
void chushi(int l , int rt){
    memset(tree[rt].m , 0, sizeof tree[rt].m);
    for(int i = 0; i < m; i ++){
        for(int j = i; j >= 0; j --){
            if(s[l][j] == '0') tree[rt].m[j][i] = 1;
            else break;
        }
        for(int j = i; j < m; j ++){
            if(s[l][j] == '0'){
                tree[rt].m[j][i] = 1;
            }
            else break;
        }
    }
}
void build(int l, int r ,int rt){

    if(l == r){
        chushi(l ,rt);
        return ;
    }
    int mid = (l + r) >> 1;
    build(l , mid , rt <<1 );
    build(mid + 1, r , rt << 1| 1);
    tree[rt] = tree[rt <<1]* tree[rt <<1|1];
}
void update(int pos, int l ,int r ,int rt){
    if(l == r){
        chushi(l , rt);

        return ;
    }

    int mid = (l + r) >> 1;
    if(pos <= mid) update(pos, l , mid, rt <<1);
    else update(pos, mid + 1, r , rt << 1|1);
    tree[rt] = tree[rt <<1]* tree[rt <<1|1];
}
int main()
{

    cin >> n >> m >> q;
    for(int i = 1; i <= n; i ++){
        cin >> s[i];
    }
    build(1,n,1);

    for(int i = 1; i <= q; i ++){
        int op, x,y;
        cin >> op >>x >> y;
        if(op == 1){
            if(s[x][y - 1] == '1') s[x][y - 1] = '0';
            else s[x][y - 1] = '1';
            update(x, 1 , n , 1);
        }
        else{

             cout << tree[1].m[x - 1][y - 1] <<endl;
        }

    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值