zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第二场)-E MAZE

    题目链接:https://ac.nowcoder.com/acm/contest/882/E

    题意:n×m的矩阵,0表示可以走,1表示墙,不能通过。有q中操作,一种是改变坐标(x,y)的状态,一种是询问从(1,x)到(n,y)有多少条路径。(n,q<=5e4,m<=10)。

    思路:dp、矩阵乘加线段树维护。

       dp[i][j]表示从第i行到(i,j)的路径数。则dp[i][j]=sum(dp[i][k](k<=j)) + sum(dp[i][k](k>j))。

         

       比如上图,dp[1][2]=dp[1][1]+dp[1][2]+dp[1][3]。

            dp[1][6]=dp[1][5]+dp[1][6]。

       因此第x行到第y行的路径数可以用转移矩阵表示,比如从第1行到第1行的转移矩阵为:

           

       其中第1行第3列的1表示从(1,1)到(1,3)有1条路经。

       用线段树维护矩阵的乘积,修改为单点修改,复杂度为O(m^3*logn),树根维护的是M1*...*Mn,即第1行到第n行的路径数,所以查询复杂度为O(1)。

       

    AC代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    typedef long long LL;
    const int maxn=50005;
    const int MOD=1e9+7;
    
    struct Mat{
        LL mat[12][12];
    };
    
    struct node{
        Mat M;
        int l,r;
    }tr[maxn<<2];
    
    int n,m,Q;
    char s[12];
    int a[maxn][12];
    
    Mat Matmul(Mat& a,Mat& b){
        Mat c;
        for(int i=1;i<=m;++i)
            for(int j=1;j<=m;++j){
                c.mat[i][j]=0;
                for(int k=1;k<=m;++k){
                    c.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%MOD;
                    c.mat[i][j]%=MOD;
                }
            }
        return c;
    }
    
    void Matupd(int v,int x){
        memset(tr[v].M.mat,0,sizeof(tr[v].M.mat));
        for(int i=1;i<=m;++i)
            if(!a[x][i]){
                tr[v].M.mat[i][i]=1;
                for(int j=i-1;j>=1&&!a[x][j];--j)
                    tr[v].M.mat[j][i]=1;
                for(int j=i+1;j<=m&&!a[x][j];++j)
                    tr[v].M.mat[j][i]=1;
            }
    }
    
    void pushup(int v){
        tr[v].M=Matmul(tr[v<<1].M,tr[v<<1|1].M);
    }
    
    void build(int v,int l,int r){
        tr[v].l=l,tr[v].r=r;
        if(l==r){
            Matupd(v,l);
            return;
        }
        int mid=(l+r)>>1;
        build(v<<1,l,mid);
        build(v<<1|1,mid+1,r);
        pushup(v);
    }
    
    void update(int v,int x){
        if(tr[v].l==tr[v].r){
            Matupd(v,x);
            return;
        }
        int mid=(tr[v].l+tr[v].r)>>1;
        if(x<=mid) update(v<<1,x);
        else update(v<<1|1,x);
        pushup(v);
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&Q);
        for(int i=1;i<=n;++i){
            scanf("%s",s);
            for(int j=1;j<=m;++j)
                a[i][j]=s[j-1]-'0';
        }
        build(1,1,n);
        while(Q--){
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if(op==1){
                a[x][y]^=1;
                update(1,x);
            }
            else
                printf("%lld
    ",tr[1].M.mat[x][y]);
        }
        return 0;
    }
  • 相关阅读:
    【转】解决在Android设备播放音频与其他应用重音的问题,并监听耳机的控制按钮
    【转】wamp 3.0.6(apache 2.4.23) 403 forbidden 解决办法
    身份证第18位(校验码)的计算方法
    【转】Win10开机密码忘了?教你破解Win10开机密码
    【转】具透 | 你可能不知道,iOS 10 有一个中国「特供」的联网权限功能
    钉钉自定义机器人 发送文本 换行 无效果
    屏蔽右键+f12
    【转】理解WebKit和Chromium: JavaScript引擎简介
    第2章 排序 | 第10节 计数排序练习题 && 基数排序
    图像处理-深入探索插值操作
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11249088.html
Copyright © 2011-2022 走看看