多校第二场 E MAZE

首先,这题的列数非常的小,很像矩阵快速幂加速dp。这题实际上也是维护了一段区间矩阵乘积的结果。

查询 O(1) 修改 O( logn * K^3 )

这里有一个需要注意的点是左乘和右乘的区别。矩阵快速幂还是 (1,n) *( n,n )这种形式比较好。

#include <bits/stdc++.h>
#define lc l,mid,x<<1
#define rc mid+1,r,x<<1|1
using namespace std;
typedef long long LL;
typedef int lint;
const lint mod = 1000000007;
const int maxn = 50005;
LL mul( LL a,LL b ){
    a *= b; a %= mod;
    return a;
}
LL ad( LL a,LL b ){
    a += b; a%= mod;
    return a;
}
struct matrix{
    int n,m;
    lint ma[11][11];
    matrix operator*( const matrix& b ){
        matrix c;
        c.n = n;c.m = b.m;
        for( int i = 1;i <= c.n;i++ ){
            for( int j = 1;j <= c.m;j++ ){
                c.ma[i][j] = 0;
                for( int k = 1;k <= m;k++ ){
                    c.ma[i][j] = ad(c.ma[i][j],mul(ma[i][k] ,b.ma[k][j]  )  );
                }
            }
        }
        return c;
    }
};
matrix tree[4*maxn];
int m,b[maxn][11];
matrix calc( int l ){
    matrix c;c.n = c.m = m;
    for( int i = 1;i <= m;i++ ){
        int f = 1;
        for( int j = i;j <= m;j++ ){
            if( b[l][j] ) f = 0;
            c.ma[j][i] = f;
        }
        f = 1;
        for( int j = i;j >= 1;j-- ){
            if( b[l][j] ) f = 0;
            c.ma[j][i] = f;
        }
    }
    return c;
}
void push_up( int x ){
    tree[x] = tree[x<<1]*tree[x<<1|1];
}
void build( int l,int r,int x ){
    if( l == r ){
        tree[x] = calc(l);
        return;
    }
    int mid = l+r >>1;
    build(lc);
    build(rc);
    push_up(x);
}
void update( int left,int right,const matrix& v,int l,int r,int x ){
    if( left <= l && right >= r ){
        tree[x] = v;
        return;
    }
    int mid = l+r>>1;
    if( left <= mid ){
        update( left,right,v,lc);
    }
    if( right > mid ){
        update( left,right,v,rc );
    }
    push_up(x);
}
matrix fi;
int main(){
    int n,q;
    scanf("%d%d%d",&n,&m,&q);
    for( int i = 1;i <= n;i++ ){
        for( int j = 1;j <= m;j++ ){
            scanf("%1d",&b[i][j]);
        }
    }
    build( 1,n,1 );
    for( int i = 1;i <= q;i++ ){
        int f,x,y;
        scanf("%d%d%d",&f,&x,&y);
        if( f==1 ){
            b[x][y] ^= 1;
            matrix c = calc(x);
            update(x, x, c, 1, n, 1);
        }else{
            fi.n = 1;fi.m = m;
            for( int i = 1;i <= m;i++ ){
                fi.ma[1][i] = 0;
            }
            fi.ma[1][x] = 1;
            matrix c = fi * tree[1];
            int ans = c.ma[1][y];
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值