2024年西安交通大學程式設計校賽
因為本人比較菜,所以只補賽時(校內訓練賽)寫了但沒寫出的題,完整題解可以參考洛谷的巨巨~:
https://www.luogu.com.cn/article/vzlnmec8
K - 崩壞:星穹鐵道
關鍵題面:Corycle 想成為星穹鐵道高手,為此他需要對自己的配隊瞭如指掌。由於角色有多種職業,同時為了方便 對角色型別進行定位,他把角色的行動模式分為了三種型別:
- 當角色行動時,只會進行普通攻擊。
- 當角色行動時,若有戰技點不少於 1 則必定釋放技能,否則進行普通攻擊。
- 不對角色的行動進行限制。
現在 Corycle 開始了一場戰鬥,他想知道當隊伍中的四名角色一共行動 n 次時,可能會有多少種不同的 行動方案。我們稱兩個行動方案不同,當且僅當存在至少一個回合中,兩個方案裡角色行為不同。這個 答案可能是一個很大的數,所以請將答案對 998244353 取模。
分析
由題目來看,這是一道狀態機模型,可以考慮 dp,但是 dp 必然要列舉每一次行動和每個狀態,複雜度為\(nk\),顯然無法過掉此題,此時我們又可以想到狀態機的 一個常用最佳化法案:矩陣,因為矩陣可以代表某個狀態滿足固定條件乘矩陣轉移到新狀態。如圖可以寫出狀態機模型和對應的矩陣方程(忽略我醜陋的字型)
而且每輪的行動方式和順序固定,不妨以輪為單位進行矩陣相乘
還有就是我沒學結構體深入的一些知識,所以先用的是函式加傳參的方式解決,ac程式碼如下
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int mat[3][6][6]={
{
{0,1,0,0,0,0},
{0,0,1,0,0,0},
{0,0,0,1,0,0},
{0,0,0,0,1,0},
{0,0,0,0,0,1},
{0,0,0,0,0,1}
},
{
{0,1,0,0,0,0},
{1,0,0,0,0,0},
{0,1,0,0,0,0},
{0,0,1,0,0,0},
{0,0,0,1,0,0},
{0,0,0,0,1,0}
},
{
{0,1,0,0,0,0},
{1,0,1,0,0,0},
{0,1,0,1,0,0},
{0,0,1,0,1,0},
{0,0,0,1,0,1},
{0,0,0,0,1,1}
}
};
int a[6][6];
int w[4];
int n,kk;
void mul(int z[][6],int x[][6],int y[][6])
{
static int t[6][6];
memset(t,0,sizeof t);
for(int i=0;i<6;++i)
for(int j=0;j<6;++j)
for(int k=0;k<6;++k)
t[i][j]=(t[i][j]+x[i][k]*y[k][j])%mod;
memcpy(z,t,sizeof t);
}
int qmi(int m[][6],int k)
{
int f[6][6]={0};
f[0][kk]=1;
while(k)
{
if(k&1)mul(f,f,a);
mul(a,a,a);
k>>=1;
}
int c=n%4;
for(int i=0;i<c;++i)
{
mul(f,f,mat[w[i]]);
}
int res=0;
for(int i=0;i<6;++i)res=(res+f[0][i])%mod;
return res;
}
signed main(){
cin>>n>>kk;
for(int i=0;i<6;++i)a[i][i]=1;
for(int i=0;i<4;++i)
{
int x;cin>>x;
x--;
w[i]=x;
mul(a,a,mat[x]);
}
cout<<qmi(a,n/4);
}
注意,此題 n 沒有說整除 4,也就是還有剩餘需要處理
題目 O. 篩法
在演算法競賽的數論知識中,我們接觸過埃拉託斯特尼篩法、線性篩法、莫比烏斯反演、杜教篩、Powerful Number 篩、Min_25 篩、洲閣篩等演算法來幫助我們最佳化一些求和/連乘的複雜度,那麼現在問題來了, 今天這道題將會使用到上述的哪個演算法呢? 現在給定正整數 n,需要你求
其中 [i ⊥ j] 表示 i, j 是否互素,即當 gcd(i, j) = 1 時,[i ⊥ j] 的值為 1,其餘情況其值為 0。
分析
具體的分析和證明在洛谷大佬的題解中已有描述,我這裡就在提一嘴賽時最容易但是很難想起的做法:打表。
因為此題的題面的迷惑性,讓人覺得這題是有什麼高深的演算法從而忘記數論本身找規律的角度思考,只需要取一個小 n,很容易就發現規律\(n^2\)即為答案(隔壁隊就是這樣過的)