解法
首先观察到极大的 ,这似乎让我们无从下手,但是不难发现 极小 ,这不禁让我们想到 是一个关键的突破口。
考虑 dp。令 表示为以第 个元素为结尾的所有区间的的和的 次方之和,即
每次加入一个元素 时,假设之前的和为 ,我们可以利用二项式定理
展开 ,即
可以发现这个式子里面的 和 都是可以通过预处理提前计算得到,而 就是 。通过这种方式,我们可以递推得到 dp 数组。最后 就是答案了。注意取模。
复杂度分析
时间复杂度
读入 ,预处理组合数 ,预处理 ,dp 过程 ,总时间复杂度 。本题下 ,因此运算量级大概是 级别的,可以通过。如果不预处理 的话,时间复杂度 。
空间复杂度
数组存储 ,组合数数组 , 数组 ,dp 数组 ,总空间复杂度 。如果不处理 数组并对 dp 数组进行滚动数组优化的话空间复杂度为 。
代码
采用滚动数组优化 dp。
#include <iostream>
#include <vector>
using namespace std;
using LL = long long;
const LL kMod = 998244353;
LL n, K, ans;
int main() {
cin.tie(0)->sync_with_stdio(0);
// 读入
cin >> n >> K;
vector<LL> a(n + 1);
for (LL i = 1; i <= n; i++) {
cin >> a[i];
}
// 预处理组合数
vector<vector<LL>> C(K + 1, vector<LL>(K + 1));
for (LL k = 0; k <= K; k++) {
C[k][0] = 1;
for (LL m = 1; m <= k; m++) {
C[k][m] = (C[k - 1][m - 1] + C[k - 1][m]) % kMod;
}
}
// 预处理 a[i]^k
vector<vector<LL>> powA(n + 1, vector<LL>(K + 1));
for (LL i = 1; i <= n; i++) {
powA[i][0] = 1;
LL x = a[i] % kMod;
for (LL k = 1; k <= K; k++) {
powA[i][k] = powA[i][k - 1] * x % kMod;
}
}
// dp 过程及统计答案
vector<LL> dp(K + 1);
for (LL i = 1; i <= n; i++) {
vector<LL> f(K + 1);
for (LL k = 0; k <= K; k++) {
for (LL m = 0; m <= k; m++) {
LL trm = C[k][m] * powA[i][k - m] % kMod, prv = dp[m];
if (m == 0) { // 注意对零次方的特殊判断
prv = (prv + 1) % kMod;
}
f[k] = (f[k] + trm * prv) % kMod;
}
}
dp = f;
ans = (ans + dp[K]) % kMod;
}
cout << ans << "\n";
return 0;
}