• 【经典】矩阵快速幂加速dp递推——namomo #1 c


    有幸打上了wls的举办的第一场比赛

    知道一定是矩阵快速幂加速dp,但是递推公式一下子有点难弄

    看了题解后才发现可以将这些六边形平放,平放之后很容易发现从第i个到第i+1的关键点是1,2:

      因为第i+1个六边形所有点的所有方向的状态,都是由第i个六边形1或2的方向推出的

    所以我们只要dp第i个六边形点1,2两个向右的方向即可

    dp[i,0]表示起点到第i个六边形1号点方向右上的最小值
    dp[i,1]:第i个六边形1号点方向右的最小值
    dp[i,2]:第i个六边形2号点方向右上的最小值
    dp[i,3]:第i个六边形2号点方向右的最小值
    那么从dp[i]->dp[i+1]就会有一个固定的递推方案
    那么就构造一个4*4的转移矩阵 
        |2 1 2 3|
    A=  |1 2 1 0|
        |0 1 2 2|
        |2 2 1 2|
    矩阵快速幂 
    [ dp[1,0],dp[1,1],dp[1,2],dp[1,3] ]*A^(n-1)=[ dp[n,0],dp[n,1],dp[n,2],dp[n,3] ]     

    特殊情况:当x==k时会有特殊情况,x==k-1,且l=4或5时会有特殊情况,是dp推不出来的,此时特判下就好

    此外,本题的矩阵快速幂比较特殊,要将原来的乘法变成加法,原来的加法变成min操作(考虑下为什么)

    ps:写这种矩阵加速dp的题比较少,花了好久才弄对。。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define N 5
    
    struct M{
        ll a[N][N];
        M(){memset(a,0x3f,sizeof a);}
    }A;
    ll F[N];
    void mul(M A,ll F[]){//F*A
        ll res[N];
        memset(res,0x3f,sizeof res);
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                res[i]=min(res[i],F[j]+A.a[j][i]);
        memcpy(F,res,sizeof res);
    }
    void mulself(M & A,M B){
        M C;
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                for(int k=0;k<4;k++)
                    C.a[i][j]=min(C.a[i][j],A.a[i][k]+B.a[k][j]);
        memcpy(A.a,C.a,sizeof C.a);
    }
    
    
    ll x,y,k,l;
    
    int main(){
        int t;cin>>t;
        while(t--){
            memset(A.a,0x3f,sizeof A.a);
            cin>>x>>y>>k>>l;
            if(x>k)swap(x,k),swap(y,l);
            if(x==k){//特殊情况 
                if(abs(y-l)==2 || abs(y-l)==4)cout<<1<<'
    ';
                else cout<<0<<'
    ';
                continue;
            }else if(k==x+1 && (l==5||l==4)){
                if(l==5)l=1;
                else l=2;
                if(abs(y-l)==2 || abs(y-l)==4)cout<<1<<'
    ';
                else cout<<0<<'
    ';
                continue;
            } 
            if(y==1)     {F[0]=0;F[1]=0;F[2]=1;F[3]=1;}
            else if(y==2){F[0]=1;F[1]=1;F[2]=0;F[3]=0;}
            else if(y==3){F[0]=1;F[1]=1;F[2]=0;F[3]=1;}
            else if(y==4){F[0]=0;F[1]=1;F[2]=1;F[3]=1;}
            else if(y==5){F[0]=1;F[1]=1;F[2]=1;F[3]=0;}
            else if(y==6){F[0]=1;F[1]=0;F[2]=1;F[3]=1;}
            A.a[0][0]=2;A.a[0][1]=1;A.a[0][2]=2;A.a[0][3]=3;
            A.a[1][0]=1;A.a[1][1]=2;A.a[1][2]=1;A.a[1][3]=0;
            A.a[2][0]=0;A.a[2][1]=1;A.a[2][2]=2;A.a[2][3]=2;
            A.a[3][0]=2;A.a[3][1]=2;A.a[3][2]=1;A.a[3][3]=2;
            //F*A^(n-1)
            ll n=k-x-1;
            while(n){
                if(n%2)mul(A,F);
                n>>=1;mulself(A,A);
            }
            ll ans=0x3f3f3f3f3f3f3f3f;
            if(l==5){
                ans=min(min(F[0],F[1]),min(F[2],F[3])+1);
            }
            else if(l==4){
                ans=min(min(F[0],F[1])+1,min(F[2],F[3]));
            }
            else if(l==1){
                ans=min(min(F[0],F[1])+1,min(F[2],F[3]+2));
            }
            else if(l==2){
                ans=min(min(F[0]+2,F[1]),min(F[2],F[3])+1);
            }
            else if(l==3){
                ans=min(min(F[0],F[1])+1,min(F[2]+2,F[3]));
            }
            else if(l==6){
                ans=min(min(F[0],F[1]+2),min(F[2],F[3])+1);
            }
            cout<<ans<<'
    ';
        }    
    } 
  • 相关阅读:
    DHTML【3】--HTML
    PS图层混合算法之六(差值,溶解, 排除)
    PS图层混合算法之五(饱和度,色相,颜色,亮度)
    curl+个人证书(又叫客户端证书)访问https站点
    密钥库文件格式[keystore]代码
    PS图层混合算法之四(亮光, 点光, 线性光, 实色混合)
    libcurl使用认证证书 https认证
    openssl指定证书密码建立连接
    PS图层混合算法之三(滤色, 叠加, 柔光, 强光)
    openssl编译出错解决
  • 原文地址:https://www.cnblogs.com/zsben991126/p/13149223.html
Copyright © 2020-2023  润新知