2025 ICPC Asia EC 网络预选赛第二场 E 题思路分享(矩阵快速幂)
题意概述
给定 \(n,m\),求满足以下条件的序列 \(a\) 数量:
-
长度为 \(n\)。
-
\(0\le a_i \le 2^m-1\)。
-
\(\bigoplus_{i=1}^{n}{a_i}=0\)。
-
任意相邻两项不等。
\(1\le n,m \le 10^9\),模 \(998244353\)。
思路
可以发现,只需要最后一个元素与前 \(i-1\) 个元素异或和相等即可。
第 \(1\) 个元素有 \(2^m\) 个选择,为保证相邻元素不等,后面 \(n-2\) 个元素每个都有 \(2^m-1\) 个选择,最后一个选择固定,因此总数为 \(2^m \cdot {(2^m-1)}^{n-2}\)。
但是这样会有不合法的情况,原因在于最后一个固定的选择可能和前一个选择相同,这种情况实际上就是前 \(n-2\) 个元素的异或和已经为 \(0\) 了,记长度为 \(n\) 的答案为 \(f(n)\),需要减去 \(f(n-2) \cdot (2^m-1)\)。
得到递推式:
\[f(n) = 2^m \cdot {(2^m-1)}^{n-2} - f(n-2)\cdot (2^m-1)
\]
令 \(2^m = x\),整理成矩阵形式:
\[\begin{pmatrix}
(x-1)^2 & 0 \\
x & 1-x
\end{pmatrix}
\begin{pmatrix}
(x-1)^{n-2} \\
f(n-2)
\end{pmatrix}
=
\begin{pmatrix}
(x-1)^n \\
f(n)
\end{pmatrix}
\]
使用矩阵快速幂优化转移即可。
时间复杂度 \(\mathcal{O}(T\cdot \log n)\)。
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 998244353;
ll qpow(ll a,ll b){
ll res = 1;
while (b){
if (b&1){
res = res*a%MOD;
}
a = a*a%MOD;
b >>= 1;
}
return res;
}
vector<vector<ll>> mul(vector<vector<ll>> m1,vector<vector<ll>> m2){
vector<vector<ll>> res(2,vector<ll>(2));
for (int i=0;i<2;i++){
for (int k=0;k<2;k++){
for (int j=0;j<2;j++){
res[i][j] = (res[i][j]+m1[i][k]*m2[k][j]%MOD)%MOD;
}
}
}
return res;
}
vector<vector<ll>> mqpow(vector<vector<ll>>& a,ll b){
vector<vector<ll>> res = {{1,0},{0,1}};
while (b){
if (b&1){
res = mul(a,res);
}
a = mul(a,a);
b >>= 1;
}
return res;
}
void solve(){
int n,m;
cin >> n >> m;
ll x = qpow(2,m);
vector<vector<ll>> temp = {{(x-1)*(x-1)%MOD,0},{x,(1-x+MOD)%MOD}};
auto mat = mqpow(temp,(n-1)/2);
if (n&1){
ll a = x-1;
ll b = 1;
ll res = (mat[1][0]*a%MOD+mat[1][1]*b%MOD)%MOD;
cout << res << '\n';
}
else{
ll a = (x-1)*(x-1)%MOD;
ll b = 0;
ll res = (mat[1][0]*a%MOD+mat[1][1]*b%MOD)%MOD;
cout << res << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号