• 洛谷 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 imes (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 imes (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;
    }
    
  • 相关阅读:
    [转]oracle数据库定时任务dbms_job的用法详解
    身份证号码的正则表达式及验证详解(JavaScript,Regex)
    js数组操作
    jq滚动到底部加载更多方法
    jq之实现轮播
    node之npm一直出错
    Jq之21点游戏
    移动端屏幕适配viewport
    meta属性
    用户体验之表单结构
  • 原文地址:https://www.cnblogs.com/wljss/p/12661316.html
Copyright © 2020-2023  润新知