洛谷 P5336 [THUSC2016]成绩单 区间DP
一个远古时期的坑终于填上了2333
我们设 \(f[l][r][x][y]\) 为使 \(l\) 到 \(r\) 这段区间到达 值域 \(\in [x,y]\) 这个情况下的最小花费. \(g[l][r]\) 为将 \([l,r]\) 全都消去的最小花费
先枚举 \(l,r,x,y\)
\(f\) 的转移:
\(1\) .由 \([l,r-1]\) 添上 \(r\) 后转移
\(2\) .枚举断点 \(k\) ,由 \(f[l][k][x][y] + g[k + 1][r]\) 转移
\(g\) 的转移:
考虑将到达的f的局面消去,由 \(f[l][r][x][y] + a + b \times (y - x) ^2\)
最后答案 \(g[1][n]\) ,注意需要离散化。
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
int n, m, a, b, len, l, r, x, y, k;
const int N = 60;
int h[N], lin[N], g[N][N], f[N][N][N][N];
int read()
{
int res = 0; char ch = getchar(); bool XX = false;
for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
return XX ? -res : res;
}
void Min(int &a, int b) {if (a > b)a = b;}
int main()
{
memset(f, 0x3f, sizeof(f)); memset(g, 0x3f, sizeof(g));
cin >> n;
cin >> a >> b;
for (int i = 1; i <= n; ++i)h[i] = read(), lin[i] = h[i];
sort(lin + 1, lin + 1 + n);
m = unique(lin + 1, lin + 1 + n) - lin - 1;
for (int i = 1; i <= n; ++i)
h[i] = lower_bound(lin + 1, lin + 1 + m, h[i]) - lin, f[i][i][h[i]][h[i]] = 0, g[i][i] = a;
for (len = 1; len <= n; ++len)
for (l = 1; l <= n - len + 1; ++l)
{
r = l + len - 1;
for (x = 1; x <= m; ++x)
for (y = x; y <= m; ++y)
{
Min(f[l][r][min(x, h[r])][max(y, h[r])], f[l][r - 1][x][y]);
for (k = l; k < r; ++k)
Min(f[l][r][x][y], f[l][k][x][y] + g[k + 1][r]);
}
for (x = 1; x <= m; ++x)
for (y = x; y <= m; ++y)
{
Min(g[l][r], f[l][r][x][y] + a + b * (lin[y] - lin[x]) * (lin[y] - lin[x]));
}
}
cout << g[1][n];
return 0;
}
updata 2020.6.14
之前的代码有点清奇,今天又考到了 所以来补一下坑
\(f[l][r][x][y]\)为将 \(l\) 到 \(r\) 删的只剩下权值 \(x\) 到 \(y\) 时最小花费, \(g[l][r]\) 为将 \(l\) 到 \(r\) 删完的最小代价。
思路和之前一样,代码可能会更好理解一些。
\(f\) 的转移:
一:枚举断点
二:枚举删除的最右边的那个区间的左端点
\(g\) 的转移:
\(f[l][r][x][y] + a + b \times (y - x) ^2\) 虽然 \(l\) 到 \(r\) 中可能没有 \(x\) 或 \(y\) ,但这样显然不优,不会成为 \(g\)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n, a, b;
const int N = 52;
int val[N];
namespace solve2
{
int tot;
int t[N], f[N][N][N][N], g[N][N];
int p2(int x) {return x * x;}
void work()
{
memset(f, 0x3f, sizeof(f)); memset(g, 0x3f, sizeof(g));
for (int i = 1; i <= n; ++i)t[i] = val[i];
sort(t + 1, t + 1 + n); tot = unique(t + 1, t + 1 + n) - t - 1;
for (int i = 1; i <= n; ++i)val[i] = lower_bound(t + 1, t + 1 + tot, val[i]) - t;
for (int i = 1; i <= n; ++i)
{
for (int x = 1; x <= tot; ++x)
for (int y = x; y <= tot; ++y)
{
if (x <= val[i] && val[i] <= y)f[i][i][x][y] = 0;
else f[i][i][x][y] = a;
}
g[i][i] = a;
}
for (int len = 2; len <= n; ++len)
for (int l = 1; l + len - 1 <= n; ++l)
{
int r = l + len - 1;
for (int x = 1; x <= tot; ++x)
for (int y = x; y <= tot; ++y)
{
for (int k = l; k < r; ++k)
{
f[l][r][x][y] = min(f[l][r][x][y]
, min(f[l][k][x][y] + g[k + 1][r]
, f[l][k][x][y] + f[k + 1][r][x][y]));
}
}
for (int x = 1; x <= tot; ++x)
for (int y = x; y <= tot; ++y)
g[l][r] = min(g[l][r], f[l][r][x][y] + a + p2(t[y] - t[x]) * b);
}
cout << g[1][n];
}
}
int main()
{
cin >> n >> a >> b;
for (int i = 1; i <= n; ++i)scanf("%d", &val[i]);
solve2::work();
return 0;
}