2026年牛客多校第三场个人题解
因为比较忙,我只做了F和两个签到题。
F
这个数据范围很容易让我们想到状压。
对于每列的状态数是 \(3^n\) 种,但是其实能够发现,真正合法的状态数不会太多。
爆搜出所有有效状态,发现在 \(n=9\) 的情况下是 \(782\) 种。
仔细想一想这个数字是怎么来的。
对于前两个位置,我们的选法是有以下六种:\(01,02,10,12,20,21\);
对于后续的任意一个位置,只有两种选择:
- 等于\(s_{i-2}\)的位置
- 等于\(3\oplus s_{i-1}\oplus s_{i-2}\) (写的比较抽象,实际上也就是那个没有出现的颜色)
即,任意一个位置都有两种选择。
故,方案数是\(6\times 2^{n-2}\)。
我们将上述的两种选择分别记成 \(0,1\),可以压缩成一个二进制的状态,且前两个位置固定成\(01\),最后可以让整个方案数乘\(6\)。
设\(dp_{k,sta}\)表示当前已经递推到了第\(k\)个位置,当前的二进制状态为 \(sta\) 的方案数。
可以考虑递推:
\(dp_{k,i}= \sum dp_{k-1,j} \times A_{j,i}\)
其中,预处理出\(A_{i,j}\)表示对于某个二进制状态\(i\)转移到二进制状态\(j\)的方案数。
对于任意 \(k-1\) 到$ k $ 的递推式的转移是相同的,于是你可以使用矩阵快速幂优化该转移。
\(dp_k=A^{k-1}\)。
这道题,我们钦定了前两个位置为\(01\),最终的方案数乘\(6\)。
设\(D=2^{n-2}\)时间复杂度为\(O(D^3\log m)\)。
似乎有一些\(n=1,m=1\)时的特判需要写。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
using ll=long long;
using namespace std;
typedef pair<int,int>pii;
const int N=800;
const int mod=998244353;
struct Matrix {
int h,l;
vector<vector<int>>v;
Matrix():v(N,vector<int>(N,0)){}
Matrix(int H,int L,bool one=0):h(H),l(L),v(H+2,vector<int>(L+2,0)){
if(one) for(int i=0;i<h;++i) v[i][i]=1;
return;
}
Matrix(int H,int L,vector<vector<int>>vv):h(H),l(L),v(vv){
}
};
Matrix operator *(const Matrix &x,const Matrix &y) {
Matrix ans(x.h,y.l);
for(int i=0;i<x.h;++i) for(int k=0;k<x.l;++k){
if(x.v[i][k]==0)continue;
for(int j=0;j<y.l;++j)ans.v[i][j]=(ans.v[i][j]+1ll*x.v[i][k]*y.v[k][j])%mod;
}
return ans;
}
Matrix ksm(Matrix x,int p) {
Matrix ans(x.h,x.l,1);
while(p) {
if(p&1) ans=ans*x;
p>>=1,x=x*x;
}
return ans;
}
ll qpow(ll x,int y){
ll res=1;
while(y){
if(y&1)res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
void Silverwolf(){
int n,m;
cin>>n>>m;
vector<int>col(n+1,0);
int cnt=0;
int res=0;
vector<string>vt;
auto dfs=[&](auto &&dfs,int pos,string now)->void{
if(pos==n+1){
vt.push_back(now);
return;
}
if(pos==1){
for(int i=0;i<=2;i++){
col[pos]=i;
char ch='0'+i;
// cout<<ch;
dfs(dfs,pos+1,now+ch);
}
}else{
for(int i=0;i<=2;i++){
if(col[pos-1]!=i){
col[pos]=i;
char ch=i+'0';
dfs(dfs,pos+1,now+ch);
}
}
}
};
dfs(dfs,1,"");
if(m==1){
cout<<vt.size()<<'\n';
return;
}
if(n==1){
//01
//02
//10
//12
//20
//21 后面每一位都有两种选择
ll ans=qpow(2,m-2);
ans=ans*6%mod;
cout<<ans<<'\n';
return;
}
int sz=vt.size();
vector<vector<int>>ma(sz/6,vector<int>(sz/6,0));
for(int i=0;i<sz/6;i++){
for(int j=0;j<sz;j++){
auto chk=[&](string a,string b)->bool{
for(int k=0;k<a.length();k++){
if(a[k]==b[k])return false;
}
return true;
};
auto get_2=[&](string b)->int{
int num=0;
for(int k=2;k<b.length();k++){
int now=b[k]-'0';
int lst=b[k-1]-'0';
int lst2=b[k-2]-'0';
if(now!=lst&&now!=lst2)num=num*2+1;
else num=num*2;
}
return num;
};
if(chk(vt[i],vt[j])){
ma[get_2(vt[i])][get_2(vt[j])]++;
}
}
}
Matrix matrix(sz/6,sz/6,ma);
//你发现状态数最多768种
Matrix a=ksm(matrix,m-1);
ll ans=0;
for(int i=0;i<sz/6;i++){
for(int j=0;j<sz/6;j++){
ans=(ans+a.v[i][j])%mod;
}
}
ans=ans*6%mod;
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// init();
// int T;cin>>T;while(T--)
Silverwolf();
return 0;
}
还做了下L和K。
浙公网安备 33010602011771号