• S


    S - Making the Grade

     POJ - 3666 

    这个题目要求把一个给定的序列变成递增或者递减序列的最小代价。

    这个是一个dp,对于这个dp的定义我觉得不是很好想,如果第一次碰到的话。

    上网看了一下题解,dp[i][j]表示前面 i 位已经是有序的了,第 i+1 位变成第j大的最小代价。

    这个转移可以保证有序这个条件。

    递增递减d两次。

    这个题目要离散化,为什么要离散化呢,推荐博客

    我以前就是感觉数据大就要离散化,不然数组存不下,不过看了这篇题解感觉他讲的很对啊。

    #include <cstring>
    #include <queue>
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <map>
    #include <vector>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 2e3 + 10;
    ll dp1[maxn][maxn], dp2[maxn][maxn];
    int a[maxn], b[maxn];
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
        sort(b + 1, b + 1 + n);
        int len = unique(b + 1, b + 1 + n) - b - 1;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= len; j++) {
                dp1[i][j] = dp2[i][j] = inf64;
            }
        }
        for (int i = 1; i <= len; i++) {
            dp1[1][i] = abs(b[i] - a[1]);
            dp2[n][i] = abs(b[i] - a[n]);
        }
        for(int i=1;i<n;i++)
        {
            ll tmp = inf64;
            for(int j=1;j<=len;j++)
            {
                tmp = min(tmp, dp1[i][j]);//这一步我感觉很巧妙,优化了一个for循环,
                //这里是再找j前面的最小的那个dp[i][j],因为dp[i][j]=min(dp[i-1][1~j])+abs()
                dp1[i + 1][j] = min(dp1[i + 1][j], tmp + abs(a[i + 1] - b[j]));
            }
        }
        ll ans = inf64;
        for (int i = 1; i <= len; i++) ans = min(ans, dp1[n][i]);
        for(int i=n;i>1;i--)
        {
            ll tmp = inf64;
            for(int j=1;j<=len;j++)
            {
                tmp = min(tmp, dp2[i][j]);
                dp2[i - 1][j] = min(dp2[i - 1][j], tmp + abs(a[i - 1] - b[j]));
            }
        }
        for (int i = 1; i <= len; i++) ans = min(ans, dp2[1][i]);
        printf("%lld
    ", ans);
        return 0;
    }
    View Code

    然后还有一个题目和这个很类似,好像比这个要难一点,所以我才先写的这个题目。

    C. Sonya and Problem Wihtout a Legend

    之前的那篇博客也有推荐

    这个题目我居然没有写出来,其实和上面基本上是一样的,只有一点点的区别,上面的是非严格的,这个是严格递增的。

    然后我不知道怎么转化,或者说我尝试过了,发现不太对。

    然后我就去搜了题解,发现有一种方法可以把严格转化成非严格就是 a[i]-i

    这样之后求非严格就可以了,然后要注意因为这个是求差值最小,所以这个不会影响答案,

    知道这个就很简单了,这个结论以后不要忘记

    #include <cstring>
    #include <queue>
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <map>
    #include <vector>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 3e3 + 10;
    ll dp[maxn][maxn];
    ll a[maxn], b[maxn];
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            a[i] -= i;
            b[i] = a[i];
        }
        sort(b + 1, b + 1 + n);
        int len = unique(b + 1, b + 1 + n) - b - 1;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= len; j++) {
                dp[i][j] = inf64;
            }
        }
        for (int i = 1; i <= len; i++) dp[1][i] = abs(a[1] - b[i]);
        for(int i=1;i<n;i++)
        {
            ll tmp = inf64;
            for(int j=1;j<=len;j++)
            {
                tmp = min(dp[i][j], tmp);
                dp[i + 1][j] = min(dp[i + 1][j], tmp + abs(a[i + 1] - b[j]));
            }
        }
        ll ans = inf64;
        for (int i = 1; i <= len; i++) ans = min(ans, dp[n][i]);
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Flip Game 分类: POJ 2015-06-15 14:59 22人阅读 评论(0) 收藏
    Dirichlet's Theorem on Arithmetic Progressions 分类: POJ 2015-06-12 21:07 7人阅读 评论(0) 收藏
    Binary Tree 分类: POJ 2015-06-12 20:34 17人阅读 评论(0) 收藏
    Self Numbers 分类: POJ 2015-06-12 20:07 14人阅读 评论(0) 收藏
    Who's in the Middle 分类: POJ 2015-06-12 19:45 11人阅读 评论(0) 收藏
    IP Address 分类: POJ 2015-06-12 19:34 12人阅读 评论(0) 收藏
    Doubles 分类: POJ 2015-06-12 18:24 11人阅读 评论(0) 收藏
    The 3n + 1 problem 分类: POJ 2015-06-12 17:50 11人阅读 评论(0) 收藏
    Counterfeit Dollar 分类: POJ 2015-06-12 15:28 19人阅读 评论(0) 收藏
    Maya Calendar 分类: POJ 2015-06-11 21:44 12人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11310143.html
Copyright © 2020-2023  润新知