题解: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;
}
posted @ 2025-06-21 16:19  P2441M  阅读(59)  评论(0)    收藏  举报