zoukankan      html  css  js  c++  java
  • hdu5009 Paint Pearls 题解

    备注:这道题完全是qbxt老师+dalao博客做法,但代码完全手敲!!!(还调了半个小时才调出来orz)

    【题目描述】(原题是英文)

    给你一个数组,每个值代表一种颜色,每次选一个区间涂颜色,代价是区间内颜色种类数的平方,涂完所有数组,问你最小代价是多少。 n<=50000

    10

    3 4 2 4 4 2 4 3 2 2

    ans=7

    【冷静分析】

    如果n的范围小点,可以考虑O(n^2)算法,比较容易想到:

    dp[i]表示到i为止,消耗的最小值

    求dp[i],只需令j从1到i-1枚举,dp[i]=dp[j]+num^2

    *num表示该区间内的颜色数

    考虑到j从i-1倒序枚举到1时,若出现重复的a[i],除第一次出现外应该删去,因为枚举到的a[i]加入num^2部分不会使num变大。(优化1)

    还有一个小优化,答案一定不会大于n,因为每个数字单独一组的答案是 n*(1)^2=n(优化2)

    可以用双向链表来实现

    扫到相同的a[i]时,令其退出链表,使i及之前的链表中,每个颜色只出现一次。(性质1)

    标程

    ​
    #include<bits/stdc++.h>
    using namespace std;
    int a[50005],dp[50005],pre[50005],nxt[50005],n;
    map<int, int>m;
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		pre[i]=i-1;nxt[i]=i+1;
    		dp[i]=9999999;//初始化 
    	}
    	dp[0]=0,pre[0]=-1;//不涂的消耗为0 
    	for(int i=1;i<=n;i++){
    		if(!m.count(a[i]))  m[a[i]]=i;//a[i]没有在之前的链表里出现过 
    		else{//之前已经有过了,踢掉之前的 
    			int tmp=m[a[i]];//优化1
    			// 踢出链表 
    			nxt[pre[tmp]]=nxt[tmp];
    			pre[nxt[tmp]]=pre[tmp];
    			m[a[i]]=i;//换成现在的,保证在链表里出现的a[i]最靠右 
    		}
    		int cnt=0;//记录颜色个数。性质1 
    		for(int j=pre[i];j!=-1;j=pre[j]){
    			cnt++;
    			dp[i]=min(dp[i],dp[j]+cnt*cnt);
    			if(cnt*cnt>i)break;//优化2 
    		}
    	}
    	cout<<dp[n]<<endl;
    	return 0;
    }
    
    ​
    
  • 相关阅读:
    思念
    空白
    curl json string with variable All In One
    virtual scroll list All In One
    corejs & RegExp error All In One
    socket.io All In One
    vue camelCase vs PascalCase vs kebabcase All In One
    element ui 表单校验,非必填字段校验 All In One
    github 定时任务 UTC 时间不准确 bug All In One
    input range & color picker All In One
  • 原文地址:https://www.cnblogs.com/erutsiom/p/9904853.html
Copyright © 2011-2022 走看看