1 条题解
-
0
题目大意
给两个长为 的正整数序列 ,以及一个长为 的整数序列 。
定义 ,。
你可以对 执行任意次以下操作:
- 选择两个相邻的位置 ,若 ,则将 改为 ,同时将 改为 。
对于所有可能经过 次或更多次操作得到的 ,求出 与 。
解题思路
一些定义与发现
特别的,假若上述对 的操作满足 ,我们称为往右操作;反之 ,我们称为往左操作。同时,定义 的情况为无法操作。
经过一次操作后, 与 中小的那个会变成 。同时,对任意一组 操作是无效的。所以,操作一次后两边独立。
我们更进一步地发现,最终序列每一个非 位置都对应了初始 的一个区间。这个区间的操作形式为:从两边不断往内操作。
第一问
先做第一问。记 表示,考虑了前 个数的最大权值是多少。每次枚举一个 转移过去。转移的时候还要枚举一个 表示最终缩在哪个数上了(记得特判最最终整个区间都是 的情况),
具体的,我们暴力 check 最终位置 的合法性容易做到暴力 。 优化的话考虑预处理出 表示,每个位置作为左/右端点往另一端操作最远能到哪里。此时判断条件就容易写成 ,时间复杂度 。
事实上,我们不需要枚举 ,只需要知道最优的 对应的贡献即可。 由于我们发现每个 对最终的 的贡献只取决于 的奇偶性,故而可以分类讨论。
记 表示 内所有偶数位置的 ,记 表示所有奇数为的 :
- ,区间最后会变为全 。
- , 是上述合法区间 内的任意偶数位置
- , 是上述合法区间 内的任意奇数位置。
预处理每个区间内的奇/偶位置最值,可以 完成上面的转移。至此,我们 完成了第一问。
第二问
第二问同理。特别的,为了防止出现两段被拼起来重复计数(其中有一段得是最终全 ),我们将对 的定义进行一点修改:
- :从 往右操作,第一次满足“操作后 ”的位置前停下。
- :从 往左操作,第一次操作后 停下。
这样可以不重不漏计数。最终这题总时间复杂度 ,空间复杂度 。如果使用 ST 表维护区间最值,空间上可以做到 。
代码实现
#include <bits/stdc++.h> #define FL(i, a, b) for (int i = (a); i <= (b); ++i) #define FR(i, a, b) for (int i = (a); i >= (b); --i) using namespace std; typedef long long ll; const int N = 5e3 + 10; const int MOD = 1e9 + 7; const ll INFLL = 1e18; int n, a[N], b[N], c[N], ic[N]; int pl[N], pr[N], v[N], iv[N]; ll mi[2][N][N], ct[2][N][N]; ll s[N], t[N], f[N], g[N]; int Qpow(int a, int b) { int ret = 1; for (; b; b >>= 1) { if (b & 1) ret = (ll)ret * a % MOD; a = (ll)a * a % MOD; } return ret; } int Inv(int x) { return Qpow(x, MOD - 2); } void Solve() { scanf("%d", &n); FL(i, 1, n) { scanf("%d", &a[i]); t[i] = t[i - 1] + (i & 1? -a[i] : a[i]); } FL(i, 1, n) { scanf("%d", &b[i]); s[i] = s[i - 1] + b[i]; } v[0] = iv[0] = 1; FL(i, 1, n) { scanf("%d", &c[i]); v[i] = (ll)v[i - 1] * c[i] % MOD; ic[i] = Inv(c[i]); iv[i] = Inv(v[i]); } FL(i, 1, n) { mi[0][i][i - 1] = mi[1][i][i - 1] = INFLL; ct[0][i][i - 1] = ct[1][i][i - 1] = 0; FL(j, i, n) { FL(k, 0, 1) { mi[k][i][j] = mi[k][i][j - 1]; ct[k][i][j] = ct[k][i][j - 1]; } mi[j & 1][i][j] = min(mi[j & 1][i][j], (ll)b[j]); ct[j & 1][i][j] = (ct[j & 1][i][j] + ic[j]) % MOD; } } FL(i, 1, n) { int d = a[i]; FL(j, i, n) { d = a[j + 1] - d; if (j == n || d <= 0) { pl[i] = j; break; } } d = a[i]; FR(j, i, 1) { d = a[j - 1] - d; if (j == 1 || d <= 0) { pr[i] = (j > 1 && !d? j - 1 : j); break; } } } fill(f, f + n + 1, -INFLL); fill(g, g + n + 1, 0); f[0] = 0, g[0] = 1; FL(i, 0, n) { FL(j, i + 1, n) { int l = max(i + 1, pr[j]), r = min(j, pl[i + 1]); if (l > r){ continue; } int h = (ll)g[i] * v[j] % MOD * iv[i] % MOD; if (t[j] - t[i] == 0) { f[j] = max(f[j], f[i] + (s[j] - s[i])); g[j] = (g[j] + h) % MOD; } else if (t[j] - t[i] > 0) { f[j] = max(f[j], f[i] + (s[j] - s[i]) - mi[0][l][r]); g[j] = (g[j] + (ll)h * ct[0][l][r]) % MOD; } else { f[j] = max(f[j], f[i] + (s[j] - s[i]) - mi[1][l][r]); g[j] = (g[j] + (ll)h * ct[1][l][r]) % MOD; } } } printf("%lld %lld\n", f[n], g[n]); } int main() { int T; scanf("%*d %d", &T); while (T--) { Solve(); } return 0; }
- 1
信息
- ID
- 2386
- 时间
- 6000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 7
- 已通过
- 1
- 上传者