【经典】矩阵快速幂加速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<<'
';
    }    
} 
原文地址:https://www.cnblogs.com/zsben991126/p/13149223.html