CF2144E1 Looking at Towers (easy version) 题解

题目传送门

思路

先考虑一个性质。根据 \(L(a)\)\(R(a)\) 的定义,\(L(a)\)\(R(a)\) 的最大值一定为 \(a\) 的最大值 \(m\)。所以我们可以考虑枚举 \(i, j\)\(i < j\)),满足 \(a_i = a_j = m\)。此时,对于 \((i, j)\) 都有选或不选两种可能,因为 \(a_i = a_j = m\),所以 \((i,j)\) 中的数对答案没有影响。故有 \(2^{j-i-1}\) 中可能(当 \(i = j\) 时有一种可能)。

先预处理出 \(L(a)\)\(R(a)\)。考虑 DP。设 \(dp_{i,j}\) 代表 \(a\) 的前 \(i\) 个元素匹配到 \(L(a)\) 的前 \(j\) 个元素时的方案数。那当:

  1. \(a_i < L(a)_j\) 时:此时 \(a_i\) 选或不选对 \(L(a)_j\) 没有影响,即 \(dp_{i,j} = 2 \times dp_{i-1,j}\)
  2. \(a_i = L(a)_j\) 时:此时 \(a_i\) 可以成为 \(L(a)_j\) 的第一个,也可以不选入 \(L(a)_j\) 但选入 \(a^′\),还可以不选入 \(a_′\),即 \(dp_{i,j} = 2 \times dp_{i-1,j} + dp_{i-1,j-1}\)
  3. \(a_i > L(a)_j\) 时:不符合题意,无解。当然,这种转移不会出现。

按此状态转移方程转移即可。边界为 \(dp_{i,0} = 1\)。同理,可以求得 \(f_{i,j}\) 代表后 \(i\) 个元素匹配到 \(R(a)\) 的前 \(j\) 个元素的方案数。

最终答案如何求?综上可得:

\[\begin{aligned} ans = \sum_{i \le j, a_i = a_j = m} 2^{max\{j-i-1,0\}} \times dp_{i - 1,|L(a)| - 1} \times f_{j + 1,|R(a)| - 1} \end{aligned} \]

即在枚举 \(i,j\) 时,对于 \((1,i-1)\) 需要匹配 \(L(a)\) 的前 \(|L(a)| - 1\) 个,对于 \(j\) 同理。\((i,j)\) 中可以随意选。时间复杂度 \(\mathcal{O}(n^2)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 5005, mod = 998244353;

int t, n;
int a[N], L[N], R[N], dp[N][N], f[N][N];

int fastPow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = (1ll * res * a) % mod;
		a = (1ll * a * a) % mod;
		b >>= 1;
	}
	return res;
}

void solve()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	int maxn = 0, szl = 0, szr = 0;
	for (int i = 1; i <= n; i++)
	{
		if (a[i] > maxn)
		{
			L[++szl] = a[i];
			maxn = a[i];
		}
	}
	for (int i = 0; i <= n + 1; i++)
		dp[i][0] = f[i][0] = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= szl; j++)
		{
			if (a[i] < L[j]) dp[i][j] = (2 * dp[i - 1][j]) % mod;
			else if (a[i] == L[j]) dp[i][j] = (2ll * dp[i - 1][j] + dp[i - 1][j - 1]) % mod;
			else dp[i][j] = dp[i - 1][j];
		}
	}
	maxn = 0;
	for (int i = n; i; i--)
	{
		if (a[i] > maxn)
		{
			R[++szr] = a[i];
			maxn = a[i];
		}
	}
	for (int i = n; i; i--)
	{
		for (int j = 1; j <= szr; j++)
		{
			if (a[i] < R[j]) f[i][j] = (2 * f[i + 1][j]) % mod;
			else if (a[i] == R[j]) f[i][j] = (2ll * f[i + 1][j] + f[i + 1][j - 1]) % mod;
			else f[i][j] = f[i + 1][j];
		}
	}
	vector<int> maxt;
	for (int i = 1; i <= n; i++)
		if (a[i] == maxn) maxt.push_back(i);
	int ans = 0;
	for (int i : maxt)
		for (int j : maxt)
			if (i <= j) ans = (ans + ((1ll * fastPow(2, max(j - i - 1, 0)) * dp[i - 1][szl - 1] % mod) * f[j + 1][szr - 1] % mod)) % mod;
	printf("%d\n", ans);
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= szl; j++)
			dp[i][j] = 0;
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= szr; j++)
			f[i][j] = 0;
}

int main()
{
	scanf("%d", &t);
	while (t--) solve();
	return 0;
}
posted @ 2026-01-04 16:45  lucasincyber  阅读(0)  评论(0)    收藏  举报