• 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;
    }
  • 相关阅读:
    sql&nbsp;一些语法&nbsp;聚合函数,…
    SQL标准
    margin:auto 和margin:0 auto的区别
    div居中
    相对问题和绝对问题
    有三行文字,每行最多80个字符,求其中大写字母,小写字母,数字,空格和其他
    输入n个字符串,将以A打头的字符串输出
    判断一个字符串是否是回文字符串
    从键盘键入5个国家的名字,按字典序输出
    输入五个字符串,输出最长的字符串
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11249088.html
Copyright © 2020-2023  润新知