题解:P12674 「LAOI-8」Count
题意
给定长度为 \(n\) 的序列 \(a\)。你需要将其划分为若干个区间,使得对于每个区间 \([l,r]\) 都有 \(a_l=a_r\)。定义一种划分方案的权值为所有区间内元素积之和,求所有合法划分方案的权值和。答案对 \(998244353\) 取模。\(1\leq n\leq 2.5\times 10^5\),\(1\leq a_i\leq 40\)。
题解
考虑 DP。令 \(f_i\) 表示 \(a[1,i]\) 的所有合法划分方案的权值和,\(g_i\) 表示 \(a[1,i]\) 的合法划分方案数。转移考虑枚举区间 \([j,i](a_j=a_i)\),则有转移:
\[\begin{align*}
f_i&=\sum_{1\leq j\leq i,a_j=a_i}f_{j-1}+g_{j-1}\prod_{k=j}^ia_k\\
g_i&=\sum_{1\leq j\leq i,a_j=a_i}g_{j-1}
\end{align*}
\]
预处理前缀积 \(pre_i\),则 \(f\) 的转移方程变为
\[f_i=\sum_{1\leq j\leq i,a_j=a_i}f_{j-1}+pre_i\sum_{1\leq j\leq i,a_j=a_i}\frac{g_{j-1}}{pre_{j-1}}
\]
开三个桶即可 \(\mathcal{O}(1)\) 转移。时间复杂度 \(\mathcal{O}(n)\)。
代码
#include <iostream>
using namespace std;
#define lowbit(x) ((x) & -(x))
#define chk_min(x, v) (x) = min((x), (v))
#define chk_max(x, v) (x) = max((x), (v))
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2.5e5 + 5, V = 45, MOD = 998244353;
inline int add(int x, int y) { return x += y, x >= MOD ? x - MOD : x; }
inline int sub(int x, int y) { return x -= y, x < 0 ? x + MOD : x; }
inline void cadd(int &x, int y) { x += y, x < MOD || (x -= MOD); }
inline void csub(int &x, int y) { x -= y, x < 0 && (x += MOD); }
int n, a[N], pre[N], ipre[N], f[N], g[N];
int b1[V], b2[V], b3[V];
inline int qpow(int a, int b) {
int res = 1;
for (; b; b >>= 1) {
if (b & 1) res = (ll)res * a % MOD;
a = (ll)a * a % MOD;
}
return res;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
g[0] = pre[0] = 1;
for (int i = 1; i <= n; ++i) cin >> a[i], pre[i] = (ll)pre[i - 1] * a[i] % MOD;
ipre[n] = qpow(pre[n], MOD - 2);
for (int i = n - 1; i >= 0; --i) ipre[i] = (ll)ipre[i + 1] * a[i + 1] % MOD;
for (int i = 1; i <= n; ++i) {
cadd(b1[a[i]], g[i - 1]);
cadd(b2[a[i]], f[i - 1]);
cadd(b3[a[i]], (ll)g[i - 1] * ipre[i - 1] % MOD);
g[i] = b1[a[i]];
f[i] = add(b2[a[i]], (ll)b3[a[i]] * pre[i] % MOD);
}
cout << f[n];
return 0;
}

浙公网安备 33010602011771号