有幸打上了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<<' '; } }