[2024-03-22]P10236 [yLCPC2024] D. 排卡
题目概述
这是一个关于如何构造序列以最大化得分之和的问题。给定一个双端队列 \(a\),通过一系列操作构造长度为 \(n\) 的序列 \(b\)。每次操作可以从队列头或队列尾取出一个元素,并将其加入序列 \(b\)。得分由数对 \((i, j)\) 的得分公式计算得到,即 \(\mathrm{score}(i,j) = i^j \bmod 998244353\)。需要找到最优策略以最大化相邻两项得分之和。
输入
- 第一行:正整数 \(T\),表示数据组数。
- 对于每组数据:
- 一行:整数 \(n\)(\(2 \leq n \leq 10^3\)),表示序列的长度。
- 一行:\(n\) 个整数 \(a_1, a_2, \dots, a_n\)(\(0 \leq a_i < 998,244,353\)),表示队列 \(a\) 中每个数字的值。
输出
- 对每组测试数据,输出一行一个整数表示答案。
示例
输入
2
5
5 3 1 4 2
6
6 5 1 4 2 3
输出
1168
15655
思路
首先,我们需要找到一种操作顺序,以最大化构造的序列 \(b\) 的相邻两项得分之和。为了解决这个问题,我们可以使用区间动态规划来计算最大得分之和。
接下来推状态转移方程:
dp[l][r][0]表示最后一个从左边进入
dp[l][r][1]表示最后一个从右边进入
dp[l][r][0] = max(dp[l + 1][r][0] + pow(a[l], a[l + 1]), dp[l + 1][r][1] + pow(a[l], a[r]));
dp[l][r][1] = max(dp[l][r - 1][0] + pow(a[r], a[l]), dp[l][r - 1][1] + pow(a[r], a[r - 1]));
注意
- 0^0=0。
- len从2开始。
- 开long long。
- 快速幂中取模
代码实现
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD = 998244353, N = 1005;
int t, n, a[N], dp[N][N][2];
int pow(int b, int e) {
if(b==0&&e==0)return 0;
int res = 1;
while (e > 0) {
if (e % 2 == 1) {
res = (1LL * res * b) % MOD;
}
b = (1LL * b * b) % MOD;
e /= 2;
}
return res%MOD;
}
main() {
cin >> t;
while (t--) {
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int len = 2; len <= n; len++) {
for (int l = 1; l + len - 1 <= n ; l++) {
int r = l + len - 1;
dp[l][r][0] = max(dp[l + 1][r][0] + pow(a[l], a[l + 1]), dp[l + 1][r][1] + pow(a[l], a[r]));
dp[l][r][1] = max(dp[l][r - 1][0] + pow(a[r], a[l]), dp[l][r - 1][1] + pow(a[r], a[r - 1]));
}
}
printf("%lld\n", max(dp[1][n][0], dp[1][n][1]));
}
return 0;
}

浙公网安备 33010602011771号