Loading

[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;
}

其他

posted @ 2024-09-15 10:22  TommyJin  阅读(17)  评论(0)    收藏  举报