智乃酱的双塔问题

题目描述

题解

不妨先不考虑询问,求从底层到顶层的方案
\(dp_{i,j}\)表示到第i层的j边的方案数(j=0/1,0代表在左边,1代表在右边)
转移方程为
\(dp_{i,0}=dp_{i-1,0}+[有‘\’的楼梯]\cdot dp_{i-1,1}\)
\(dp_{i,1}=dp_{i-1,1}+[有‘/’的楼梯]\cdot dp_{i-1,0}\)
不难写出一个矩阵

\[\begin{pmatrix} dp_{i-1,0}&dp_{i-1,1}\\ \end{pmatrix} *\begin{pmatrix} 1&[if \quad '/']\\ [if\quad '\']&1\\ \end{pmatrix} = \begin{pmatrix} dp_{i,0}&dp_{i,1}\\ \end{pmatrix} \]

因此可见每一层的转移都是固定的,那么我们可以用前缀和来维护
所以对于每次询问,只要求得区间的矩阵乘积即可
得到区间的矩阵乘积可以用线段树维护,也可以直接用矩阵求逆来求,这里用的是前者

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long 
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=1e9+7;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct Matrix{
    int l,r;
    ll a[3][3];
    Matrix (){
        l=2,r=2;
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++)a[i][j]=(i==j);
        }
    }
    void zero(){memset(a,0,sizeof(a));}
    Matrix operator*(Matrix m1){
        Matrix m;m.zero();
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++){
                for(int k=0;k<r;k++){
                    (m.a[i][j]+=a[i][k]*m1.a[k][j]%MOD)%=MOD;
                }
            }
        }
        return m;
    }
    Matrix operator+(Matrix m1){
        Matrix m;m.zero();
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++){
                (m.a[i][j]+=(a[i][j]+m1.a[i][j])%MOD)%=MOD;
            }
        }
        return m;
    }
    Matrix operator^(ll y){
        Matrix sum,x;
        memcpy(x.a,a,sizeof(a));
        while(y){
            if(y&1)sum=sum*x;
            y>>=1;x=x*x;
        }
        return sum;
    }
    void print(){
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++)printf("%lld ",a[i][j]);
            printf("\n");
        }
    }
}ls[2];
int n,m,biao[maxn];
struct tree{
    Matrix sum;
}tr[maxn];
void build(int k,int l,int r){
    if(l==r){
        tr[k].sum=ls[biao[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
    return ;
}
Matrix query(int k,int l,int r,int L,int R){
    Matrix now;
    if(L>r || l>R)return now;
    if(L<=l && r<=R)return tr[k].sum;
    int mid=(l+r)>>1;
    now=query(k<<1,l,mid,L,R)*query(k<<1|1,mid+1,r,L,R);
    return now;
}
int main(){
    n=read();m=read();char ch[maxn];scanf("%s",ch);
    ls[0].a[0][1]=1;ls[1].a[1][0]=1;
    for(int i=1;i<n;i++){
        if(ch[i-1]=='/')biao[i]=0;
        else biao[i]=1;
    }
    build(1,1,n-1);
    while(m--){
        int hs=read(),ht=read(),ps=read(),pt=read();
        Matrix y;y.l=1;
        if(ps==1)y.a[0][0]=0,y.a[0][1]=1;
        Matrix now=query(1,1,n-1,hs,ht-1);
        Matrix ans=y*now;
        printf("%lld\n",ans.a[0][pt]);
    }
    return 0;
}

待修改的

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long 
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=1e9+7;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct Matrix{
    int l,r;
    ll a[3][3];
    Matrix (){
        l=2,r=2;
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++)a[i][j]=(i==j);
        }
    }
    void zero(){memset(a,0,sizeof(a));}
    Matrix operator*(Matrix m1){
        Matrix m;m.zero();
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++){
                for(int k=0;k<r;k++){
                    (m.a[i][j]+=a[i][k]*m1.a[k][j]%MOD)%=MOD;
                }
            }
        }
        return m;
    }
    Matrix operator+(Matrix m1){
        Matrix m;m.zero();
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++){
                (m.a[i][j]+=(a[i][j]+m1.a[i][j])%MOD)%=MOD;
            }
        }
        return m;
    }
    Matrix operator^(ll y){
        Matrix sum,x;
        memcpy(x.a,a,sizeof(a));
        while(y){
            if(y&1)sum=sum*x;
            y>>=1;x=x*x;
        }
        return sum;
    }
    void print(){
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++)printf("%lld ",a[i][j]);
            printf("\n");
        }
    }
}ls[2];
int n,m,biao[maxn];
struct tree{
    Matrix sum;
}tr[maxn];
void build(int k,int l,int r){
    if(l==r){
        tr[k].sum=ls[biao[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
    return ;
}
void update(int k,int l,int r,int P,int now){
    if(l>P || r<P)return ;
    if(l==r){
        tr[k].sum=ls[now];
        return ;
    }
    int mid=(l+r)>>1;
    update(k<<1,l,mid,P,now);update(k<<1|1,mid+1,r,P,now);
    tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
    return ;
}
Matrix query(int k,int l,int r,int L,int R){
    Matrix now;
    if(L>r || l>R)return now;
    if(L<=l && r<=R)return tr[k].sum;
    int mid=(l+r)>>1;
    now=query(k<<1,l,mid,L,R)*query(k<<1|1,mid+1,r,L,R);
    return now;
}
int main(){
    n=read();m=read();char ch[maxn];scanf("%s",ch);
    ls[0].a[0][1]=1;ls[1].a[1][0]=1;
    for(int i=1;i<n;i++){
        if(ch[i-1]=='/')biao[i]=0;
        else biao[i]=1;
    }
    build(1,1,n-1);
    while(m--){
        int op=read();
        if(op==1){
            int hs=read(),ht=read(),ps=read(),pt=read();
            Matrix y;y.l=1;
            if(ps==1)y.a[0][0]=0,y.a[0][1]=1;
            Matrix now=query(1,1,n-1,hs,ht-1);
            Matrix ans=y*now;
            printf("%lld\n",ans.a[0][pt]);
        }
        else {
            int kk=read();
            char cc[2];scanf("%s",cc);
            int now=0;
            if(cc[0]!='/')now=1;
            update(1,1,n-1,kk,now);
        }
    }
    return 0;
}

DDP
将矩阵乘法看作floyd来求最短距离,注意初始化矩阵与单位矩阵不同

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long 
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=1e9+7;
const ll inf=1LL<<61;
const double pi=acos(-1);
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct Matrix{
    int l,r;
    ll a[3][3];
    Matrix (){
        l=2,r=2;
        //初始化不同
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++)a[i][j]=inf;
            a[i][i]=0;
        }
    }
    void init(){
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++)a[i][j]=inf;
        }
    }
    Matrix operator*(Matrix m1){
        //FLoyd
        Matrix m;m.init();
        for(int i=0;i<l;i++){
            for(int j=0;j<r;j++){
                for(int k=0;k<r;k++){
                    if(a[i][k]==inf || m1.a[k][j]==inf)continue;
                    m.a[i][j]=min(m.a[i][j],(a[i][k]+m1.a[k][j]));
                }
            }
        }
        return m;
    }
    void update(ll a1,ll a2,ll a3,ll a4){
        a[0][0]=a1;a[0][1]=a2;
        a[1][0]=a3;a[1][1]=a4;
    }
};
int n,m,biao[maxn];
char ch[maxn];
ll val[maxn][4];
struct tree{Matrix sum;}tr[maxn];
void build(int k,int l,int r){
    if(l==r){
        if(ch[l]=='/')tr[k].sum.update(val[l][0],val[l][2],inf,val[l][1]);
        else tr[k].sum.update(val[l][0],inf,val[l][2],val[l][1]);
        return ;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
    return ;
}
void update(int k,int l,int r,int P){
    if(l>P || r<P)return ;
    if(l==r){
        if(ch[l]=='/')tr[k].sum.update(val[l][0],val[l][2],inf,val[l][1]);
        else tr[k].sum.update(val[l][0],inf,val[l][2],val[l][1]);
        return ;
    }
    int mid=(l+r)>>1;
    update(k<<1,l,mid,P);update(k<<1|1,mid+1,r,P);
    tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
    return ;
}
Matrix query(int k,int l,int r,int L,int R){
    Matrix now;
    if(L>r || l>R)return now;
    if(L<=l && r<=R)return tr[k].sum;
    int mid=(l+r)>>1;
    now=query(k<<1,l,mid,L,R)*query(k<<1|1,mid+1,r,L,R);
    return now;
}
int main(){
    n=read();m=read();scanf("%s",ch+1);
    for(int i=1;i<n;i++){
        val[i][0]=read();val[i][1]=read();val[i][2]=read();
    }
    build(1,1,n-1);
    while(m--){
        int op=read();
        if(op==2){
            int hs=read(),ht=read(),ps=read(),pt=read();
            Matrix ans=query(1,1,n-1,hs,ht-1);
            if(ans.a[ps][pt]==inf)ans.a[ps][pt]=-1;
            printf("%lld\n",ans.a[ps][pt]);
        }
        else if(op==0){
            int hh=read();cin>>ch[hh];
            update(1,1,n-1,hh);
        }
        else {
            int hh=read();
            val[hh][0]=read();val[hh][1]=read();val[hh][2]=read();
            update(1,1,n-1,hh);
        }
    }
    return 0;
}

posted @ 2022-02-07 18:43  I_N_V  阅读(111)  评论(0编辑  收藏  举报