• hdu-5009 Paint Pearls DP+双向链表 with Map实现去重优化


    http://acm.hdu.edu.cn/showproblem.php?pid=5009

    题目要求对空序列染成目标颜色序列,对一段序列染色的成本是不同颜色数的平方。

    这题我们显然会首先想到用DP去解决,dp[i] = min( dp[i] , dp[j] + cost(i , j) )。但是枚举ij的复杂的高达n^2,不能接受,我们就考虑去优化它。

    首先比较容易想到的是,去除连续重复元素,可以把它们当作同一个点处理。

    此外在遍历j的过程中如果当前序列颜色不同的数量平方大于当前dp[i],显然已经没有一并涂色以及继续扩充序列的必要了(随着序列数的增长,不同颜色的数量是单调递增的,必然在之后不会出现小于dp[i]的情况。

    但是这样并不能把复杂的降低至sqrt(n)*n,因为我们枚举的子序列会有重复元素,所以并不是每次j的变化都会来带不同颜色数的增长,比如24242424这种。那么我们考虑这种情况该如何优化,我们先换一个比较容易理解的例子9871341,当我们的i指向最后一个1的时候,我们的j开始向前遍历,当遍历到上一个i的时候,其实我们已经知道,这个i我们把它包含进去是没有成本的(因为之前已经有1了,并不会使不同颜色的数增加)所以我们应该不假思索地加入这个数。但是计算机是很蠢的,它每次依旧会遍历到它,别看这遍历一个单位很快,像24242424这种就会导致计算机大量重复地枚举了。为此我们模拟一个双向链表,在枚举i地过程中,我们维护前缀序列地链表全都是不同的元素,这个实现起来其实并不难,因为i每次增长最多会增加一个重复元素,相应的我们也只需要去除一个重复元素(即上一次出现当前值的那个位置)。然后在遍历j的时候只需要遍历链表就好了。这样我们保证j遍历过程中每次都能增加一个不同颜色,复杂的自然降低到n*sqrt(n)了。

    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstdio>
    #define LL int
    using namespace std;
    const int N=50005;
    const LL inf=1e8+1;
    LL arr[N];
    LL dp[N];
    int pre[N];
    int nex[N];
    int main()
    {
        cin.sync_with_stdio(false);
        int n;
        while(cin>>n)
        {
            int p=0;
            for(int i=0; i<n; i++)
            {
                int c;
                //c=_read();
                cin>>c;
                if(i==0||arr[p]==c)
                    arr[p]=c;
                else
                    arr[++p]=c;
            }
            map<LL,int> unq;
            int rk=0;
            for(int i=0; i<=p; i++)
            {
                map<LL,int>::iterator it=unq.find(arr[i]);
                if(it!=unq.end())
                    arr[i]=it->second;
                else
                {
                    unq[arr[i]]=rk;
                    arr[i]=rk;
                    rk++;
                }
                pre[i]=i-1;
                nex[i]=i+1;
            }
            dp[p+1]=0;
            map<LL,int> v;
            for(int i=p; i>=0; i--)
            {
                LL ans=inf;
                if(v.find(arr[i])==v.end())
                    v[arr[i]]=i;
                else
                {
                    int ix=v[arr[i]];
                    nex[pre[ix]]=nex[ix];
                    pre[nex[ix]]=pre[ix];
                    v[arr[i]]=i;
                }
                int rx;
                int cnt=0;
                for(int j=i; j!=p+1; j=nex[j])
                {
                    //cout<<j<<endl;
                    cnt++;
                    LL p2=cnt*cnt;
                    if(p2>ans)
                        break;
                    if(p2+dp[nex[j]]<ans)
                    {
                        ans=p2+dp[nex[j]];
                        rx=j;
                    }
                    //ans=min(ans,(LL)(xx+dp[j+1]));
                    //cout<<ans<<' '<<s.size()<<' '<<dp[j+1]<<endl;
                }
                dp[i]=ans;
                //cout<<dp[i]<<' '<<i<<' '<<rx<<endl;
            }
            //printf("%d
    ",dp[0]);
            cout<<dp[0]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    weexpack build android 和 weexpack run android 报错 及 解决方案
    weexapp 开发流程(三)其他页面创建
    svn 创建分支、切换分支 及 合并分支 操作
    github 新建远程仓库 及 删除远程仓库
    photoshop 前端常用技巧
    vue2.0 常用的 UI 库
    weex 小结
    Android-studio 连接真机 调试weex项目
    js中Math之random,round,ceil,floor的用法总结
    基于canvas图像处理的图片 灰色图像
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/8604648.html
Copyright © 2020-2023  润新知