CF1580D Subsequence
CF1580D Subsequence
题目大意:
Alice 有一个长度为 \(n\) 的整数序列 \(a\),所有元素都是不同的。她将选择一个长度为 \(m\) 的 \(a\) 的子序列,并将一个子序列 \(a_{b1},a_{b2},...,a_{bm}\) 的价值定义为
\(\sum_{i = 1}^m (m \cdot a_{b_i}) - \sum_{i = 1}^m \sum_{j = 1}^m f(\min(b_i, b_j), \max(b_i, b_j))\)
其中 \(f(i,j)\) 表示 \(\min(a_i,a_{i+1},..., a_j)\)。
Alice 希望你能帮助她将她所选择的子序列的价值最大化。
思路:
考虑 尘封已久的 DP。
令 \(dp_{l,r,k}\) 为区间 \([l,r]\) 中,选择 \(k\) 个值作为子序列的最大值。下令 \(pos\) 为区间 \([l,r]\) 中最小的位置。
易得:
\[dp_{l,pos-1,x} + dp_{pos+1,r,k-x} - 2 \times x \times (k - x) \times a_{pos} \rightarrow dp_{l,r,k}\\
dp_{l,pos-1,x} + dp_{pos+1,r,k-x} + m \times a_{pos} - (2 \times (x + 1) \times (k - x + 1) - 1) \times a_{pos} \rightarrow dp_{l,r,k+1}
\]
然后就可以笛卡尔树上DP啦!
代码中函数
Solve(l,r)返回vector类型的res,其中:res[i]表示题解中 \(dp_{l,r,i}\) 的值。
代码:
#include <bits/stdc++.h>
#define ll long long
#define INF 9223372036854775807
#define Maxn 4005
using namespace std;
ll n, m, a[Maxn];
vector<ll> Solve(ll l, ll r) {
// cerr << l << " " << r << "\n";
vector<ll> res(r - l + 2, -INF);
res[0] = 0;
if (l > r) {
// cerr << "IN\n";
return res;
}
ll minl = INF, pos = l - 1;
for (ll i = l; i <= r; i ++) {
if (a[i] < minl) { pos = i; }
minl = min(minl, a[i]);
}
vector<ll> lft = Solve(l, pos - 1), rgt = Solve(pos + 1, r);
// cerr << l << " " << r << " : " << lft.size() << " " << rgt.size() << "\n";
for (int i = 0; i < (int)lft.size(); i ++) {
for (int j = 0; j < (int)rgt.size(); j ++) {
res[i + j] = max(res[i + j], lft[i] + rgt[j] - 2 * i * j * a[pos]);
res[i + j + 1] = max(res[i + j + 1], lft[i] + rgt[j] + m * a[pos] - (2 * (i + 1) * (j + 1) - 1) * a[pos]);
}
} return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
} cout << Solve(1, n)[m];
return 0;
}

浙公网安备 33010602011771号