题解都说用sum[i][j] 表示 除去i到j 的功率的剩下的攻率和 然后每次更新就加上就行了
这不是逆的推的么? 然后我就觉得正的推应该也行 就用F[i][j][i]表示 关闭 i 到 j 的然后结束位置是 i 的时间(这个时间是在最少功率的基础上的) 然后用f[i][j][i] 表示dp的那个东东 然后就只有70分吖 为啥啊 感觉应该一样吧..
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 55;
ll f[maxn][maxn][maxn];
ll F[maxn][maxn][maxn];
ll rote[maxn], wi[maxn];
ll lu(int a, int b) {
return abs(rote[a] - rote[b]);
}
int main() {
int n, c;
cin >> n >> c;
for (int i = 1; i <= n; i++) {
scanf("%lld%lld", rote + i, wi + i);
}
memset(f, 0x3f, sizeof(f));
f[c][c][c] = 0;
// F 不需要初始化 因为如果当前的没有遍历过那么 f 就已经是最大的了
for (int len = 1; len <= n; len++) {
for (int i = c - len + 1; i <= c; i++) {
int l = max(1, i), r = min(i + len - 1, n);// l表示区间左端点, r 为右端点
if (f[l][r][l] > f[l + 1][r][r] + (lu(r, l) + F[l + 1][r][r]) * wi[l]) {
f[l][r][l] = f[l + 1][r][r] + (lu(r, l) + F[l + 1][r][r]) * wi[l];
F[l][r][l] = lu(r, l) + F[l + 1][r][r];
}
if (f[l][r][l] > f[l + 1][r][l + 1] + (lu(l + 1, l) + F[l + 1][r][l + 1]) * wi[l]) {
f[l][r][l] = f[l + 1][r][l + 1] + (lu(l + 1, l) + F[l + 1][r][l + 1]) * wi[l];
F[l][r][l] = lu(l + 1, l) + F[l + 1][r][l + 1];
}
if (f[l][r][r] > f[l][r - 1][r - 1] + (lu(r - 1, r) + F[l][r - 1][r - 1]) * wi[r]) {
f[l][r][r] = f[l][r - 1][r - 1] + (lu(r - 1, r) + F[l][r - 1][r - 1]) * wi[r];
F[l][r][r] = lu(r - 1, r) + F[l][r - 1][r - 1];
}
if (f[l][r][r] > f[l][r - 1][l] + (lu(l, r) + F[l][r - 1][l]) * wi[r]) {
f[l][r][r] = f[l][r - 1][l] + (lu(l, r) + F[l][r - 1][l]) * wi[r];
F[l][r][r] = lu(l, r) + F[l][r - 1][l];
}
}
}
cout << min(f[1][n][1], f[1][n][n]) << endl;
return 0;
}