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\) 个元素时的方案数。那当:
- \(a_i < L(a)_j\) 时:此时 \(a_i\) 选或不选对 \(L(a)_j\) 没有影响,即 \(dp_{i,j} = 2 \times dp_{i-1,j}\);
- \(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}\);
- \(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;
}

浙公网安备 33010602011771号