校内 C218

T2 与 T4 蛮有意思的,写一下。

传送门

T2

题目描述:

已知两个序列 \(a\)\(b\),可以进行一次操作:将其中任意一个序列的一个区间翻转。求这样的 \(\sum{a_i \times b_i}\) 的最大值。长度 <= 5000;

解析

我们考虑 DP。设 \(f[i][j]\) 表示翻转两个序列的任意一个序列的区间,求得的最大值。目标:\(\max{f[i][j]}\)

考虑如何转移,我们先假设答案只用翻转 \(a\)

枚举每一个数作为区间的中点,那么分两种情况:

  1. 区间大小为奇数,那么我们只用枚举 \(i\) 作为中点,与他到区间左右端点的长度,设为 \(j\)。那么从 \(f[i - j + 1][i + j - 1]\) 转移到 \(f[i - j][i + j]\) 也就相当于多将 swap(a[i - j], a[i + j]),所需的花费,就应该是 \(a[i + j] \times b[i - j] + a[i - j] \times b[i + j] - a[i + j] \times b[i + j] - a[i - j] \times b[i - j]\)。那么即为 \(f[i - j][i + j] = f[i - j + 1][i + j - 1] + a[i + j] \times b[i - j] + a[i - j] \times b[i + j] - a[i + j] \times b[i + j] - a[i - j] \times b[i - j]\),初值即使 \(f[i][i] = sum\)

  2. 区间大小为偶数,那么中点有两个 \(i\)\(i + 1\),同上面的思想。初值为 \(f[i][i + 1] = sum - a[i] * b[i] - a[i + 1] * b[i + 1] + a[i] * b[i + 1] + a[i + 1] * b[i];\)

而因为我们只是假设翻转 \(a\),所以我们再做一次 DP 翻转 \(b\),答案取最大值即可。

#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;

const int N = 5500;
int n, a[N], b[N], f[N][N], sum, ans;

signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) cin >> b[i], sum += a[i] * b[i];
	ans = sum;
	for (int i = 1; i <= n; i++) {
		f[i][i] = sum;
		f[i][i + 1] = sum - a[i] * b[i] - a[i + 1] * b[i + 1] + a[i] * b[i + 1] + a[i + 1] * b[i];
		for (int j = 1; j + i <= n && i - j; j++) f[i - j][i + j] = f[i - j + 1][i + j - 1] - a[i - j] * b[i - j] - a[i + j] * b[i + j] + a[i + j] * b[i - j] + a[i - j] * b[i + j], ans = max(ans, f[i - j][i + j]);
		for (int j = 1; j + i + 1 <= n && i - j; j++) f[i - j][i + j + 1] = f[i - j + 1][i + j] - a[i - j] * b[i - j] - a[i + j + 1] * b[i + j + 1] + a[i + j + 1] * b[i - j] + a[i - j] * b[i + j + 1], ans = max(ans, f[i - j][i + j + 1]);
	}
	cout << ans;
	return 0;
}

T4

题目描述

压缩长度为 \(n \le 5000\)\(1 \sim k \le 998244353\) 种字符组成的字符串。求出压缩后长度 \(< n\) 的种类,对 \(998244353\) 取模。

解析

DP。设 \(f[i][j]\) 表示前 \(i\) 位压缩后成为 \(j\) 的个数。

首先考虑 \(i \le 9\) 的情况。\(f[i][j] += f[i - 1][j] + f[i - 1][j - 2] \times (k - 1)\)。其中 \(f[i - 1][j]\) 表示当前的字符与上一个相同的情况,因为 \(i \le 9\) 所以最多是形如 \(a9\) 这样的,还是 \(2\) 位,\(j\) 不变。\(f[i - 1][j - 2] \times (k - 1)\) 表示与上一位不同,也很好理解,因为与上一位不同就要多出 \(2\) 个字符,而且当前字符有 \(k - 1\) 种情况,所以是 \(j - 2\)。那么初值即为 \(f[1][2] = k\)

\(10 \le i \le 99\)。首先肯定会有 \(f[i][j] += f[i - 1][j] + f[i - 1][j - 2] \times (k - 1)\) 这个方程。单这只是每次增添两位。我们考虑拎出来 \(i - 9 \sim i\) 出来与 \(i - 10\) 不同。这样我们就会形成形如 \(a10\)\(3\) 位字符串。那么我们就又加上了 \(f[i - 10][j - 3] \times (k - 1)\)。但这就对了吗?显然不是,因为加的 \(f[i - 1][j]\) 包含了 \(i - 9 \sim 1\) 位为开头的情况,也就是 \(a10\) 但在程序中他会既属于压缩后为 \(2\) 位又是压缩后为 \(3\) 位的字符串,所以我们要减去 \(i\) 位与 \(i - 9 \sim 1\) 相同的可能。也就是减去 \(f[i - 10][j - 2] \times (k - 1)\),因为是第 \(i - 9\) 位与 \(i - 10\) 位不同的情况,这样连起来刚好 \(10\) 个。刚好不合法。初始化 \(f[10][3] = k\)

剩下的同上。

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

const int N = 5005, mod = 998244353;
int n, f[N][N], k, ans, s[N], sum[N][N];

signed main() {
	ios::sync_with_stdio(0);
	cin >> n >> k;
	f[1][2] = k; f[10][3] = k; f[100][4] = k; f[1000][5] = k;
	for (int i = 1; i <= 9; i++) s[i] = 2;
	for (int i = 10; i <= 99; i++) s[i] = 3;
	for (int i = 100; i <= 999; i++) s[i] = 4;
	for (int i = 1000; i <= 5000; i++) s[i] = 5;
	for (int i = 2; i <= n; i++) {
		for (int j = s[i]; j <= n; j++) {
			f[i][j] += f[i - 1][j - 2] * (k - 1);
			f[i][j] %= mod;
			f[i][j] += f[i - 1][j];
			f[i][j] %= mod;
			if (i >= 10) f[i][j] -= f[i - 10][j - 2] * (k - 1);
            f[i][j] += mod;
            f[i][j] %= mod;
			if (i >= 100) f[i][j] -= f[i - 100][j - 3] * (k - 1);
            f[i][j] += mod;
            f[i][j] %= mod;
            if (i >= 1000) f[i][j] -= f[i - 1000][j - 4] * (k - 1);
			f[i][j] += mod;
			f[i][j] %= mod;

			if (i >= 10) f[i][j] += f[i - 10][j - 3] * (k - 1);
			f[i][j] %= mod;
            if (i >= 100) f[i][j] += f[i - 100][j - 4] * (k - 1);
            f[i][j] %= mod;
            if (i >= 1000) f[i][j] += f[i - 1000][j - 5] * (k - 1);
            f[i][j] %= mod;
		}
	}
	for (int i = 1; i < n; i++) {
		ans += f[n][i];
		ans %= mod;
	}
	cout << ans << endl;
	return 0;
}
posted @ 2023-11-29 13:10  lucky_cloud  阅读(21)  评论(0编辑  收藏  举报