P10528 [XJTUPC2024] 崩坏:星穹铁道 题解
题目大意
给定
思路
先考虑最基本的动态规划,
如果
同理,可得
发现
根据转移方程,可以得到转移矩阵:
若
若
若
由于战斗过程是四个人轮流发动攻击,并且每个人所对应的矩阵可能不同,因此可以将四次行动绑在一起作为一回合,建立一个新的矩阵作为回合的转移矩阵,对这个新矩阵进行快速幂,后面再将不满一回合的操作另外统计进去就可以了(另外,还需要构造一个初始矩阵,进行一次乘法初始矩阵除
代码实现
(出于习惯代码里矩阵的下标是从
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10+5,M=998'244'353;
struct matrix{
int sizeh,sizel;
ll val[N][N];
matrix(){
sizeh=0,sizel=0;
memset(val,0,sizeof val);
}
matrix(int X){//单位方阵
sizeh=sizel=X;
for(int i=1;i<=X;i++){
for(int j=1;j<=X;j++){
if(i==j)val[i][j]=1;
else val[i][j]=0;
}
}
}
matrix operator*(const matrix &A)const{
matrix ret;
ret.sizeh=this->sizeh;
ret.sizel=A.sizel;
for(int i=1;i<=this->sizeh;i++){
for(int j=1;j<=A.sizel;j++){
for(int k=1;k<=this->sizel;k++){
ret.val[i][j]+=(this->val[i][k]*A.val[k][j])%M;
ret.val[i][j]%=M;
}
}
}
return ret;
}
};
matrix qpow(matrix A,ll k){
matrix ret(A.sizeh);
while(k){
if(k&1)ret=ret*A;
A=A*A;
k>>=1;
}
return ret;
}
ll n,k;
int a[N];
matrix t[N];//三种类型的转移矩阵
ll cnt;
int main(){
cin>>n>>k;
//这里实现下标是从1开始的
t[1].sizeh=t[1].sizel=t[2].sizeh=t[2].sizel=t[3].sizeh=t[3].sizel=6;
t[1].val[1][2]=t[1].val[2][3]=t[1].val[3][4]=t[1].val[4][5]=t[1].val[5][6]=t[1].val[6][6]=1;
t[2].val[1][2]=t[2].val[2][1]=t[2].val[3][2]=t[2].val[4][3]=t[2].val[5][4]=t[2].val[6][5]=1;
t[3].val[1][2]=t[3].val[2][3]=t[3].val[3][4]=t[3].val[4][5]=t[3].val[5][6]=t[3].val[6][6]=1;
t[3].val[2][1]=t[3].val[3][2]=t[3].val[4][3]=t[3].val[5][4]=t[3].val[6][5]=1;
matrix ans(6),start;
start.val[1][k+1]=1;//初始矩阵
start.sizeh=start.sizel=6;
for(int i=1;i<=4;i++){
cin>>a[i];
ans=ans*t[a[i]];
}
ans=start*qpow(ans,n/4);
n%=4;
for(int i=1;i<=n;i++)ans=ans*t[a[i]];
for(int i=1;i<=6;i++)cnt=(cnt+ans.val[1][i])%M;
cout<<cnt;
return 0;
}