看似矩阵快速幂,实则推式子 + 普通快速幂。
难度普及+/提高
算法快速幂
日期2025-09-24
题意简述
给定两个长度为 n 的数列 {a1,a2,…,an},{b1,b2,…,bn},n×n 的矩阵 A 满足 Aij=ai×bj。
求:(∑i=1n∑j=1nAijk)modM,其中 M=998244353。
范围:1≤n≤105;0≤k≤M;ai,bi∈Z,∣ai∣,∣bi∣≤109;
(M=998244353≈109)
本题中 A0 为单位矩阵。
如果用常规矩阵快速幂,求一次矩阵乘法 O(n2),总共 O(nlogn2),显然不行。
考虑推式子。
Aij2=Aij×Aij=∑k=1naibk×akbj=aibj∑k=1nakbk;
不妨记 σ=∑k=1nakbk,
则 Aij2=aibjσ。
类似地,Aij4=Aij2×Aij2=∑k=1naibkσ×akbjσ=aibjσ2∑k=1naibj=aibjσ3。
不难发现,Aijk=aibjσk−1。
故:
i=1∑nj=1∑nAijk=i=1∑nj=1∑naibjσk−1=(i=1∑nai)⋅(j=1∑nbj)⋅(i=1∑naibi)k−1.
所以我们只需要用 O(n) 的时间统计三个 ∑ 的值,然后对 σ 用快速幂,总计 O(n+logn)=O(n),可以通过本题。
-
注意 ai,bi 可能小于零,需要在输入时取一次 ai←(aimodM+M)modM。
-
考虑边界情况,k=0 时 ans=n。
用时 73 ms 内存 1.92 MB
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 998244353;
const int MAXN = 1e5 + 1;
ll a[MAXN], b[MAXN];
ll qpow(ll a, ll n) {
ll res = 1;
while (n) {
if (n & 1) res = (res * a) % MOD;
a = (a * a) % MOD;
n >>= 1;
}
return res;
}
int main() {
ll n, k, o;
cin >> n >> k;
ll suma = 0, sumb = 0, sumab = 0;
for (ll i = 1; i <= n; i++) {
cin >> o;
a[i] = (o % MOD + MOD) % MOD;
suma = (suma + a[i]) % MOD;
}
for (ll i = 1; i <= n; i++) {
cin >> o;
b[i] = (o % MOD + MOD) % MOD;
sumb = (sumb + b[i]) % MOD;
}
for (ll i = 1; i <= n; i++) {
sumab = (sumab + ((a[i] * b[i]) % MOD)) % MOD;
}
if (k == 0) {
cout << n << endl;
} else {
sumab = qpow(sumab, k - 1);
ll ans = (suma * sumb) % MOD;
cout << (ans * sumab) % MOD << endl;
}
return 0;
}