hdu5009(dp+双向链表优化)

来源:互联网 发布:金属材料牌号查询软件 编辑:程序博客网 时间:2024/06/15 02:00

链接:点击打开链接

题意:给出一个长度是n的区间中每一个元素的颜色,每次只能选一个区间染色,染色的代价为这个区间不同颜色数的平方,问最小代价

代码:

#include <set>#include <map>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>using namespace std;const long long INF=0x3f3f3f3f3f3f3f3f;long long a[100005],dp[100005];long long pre[100005],nex[100005];int main(){                                     //dp[i]表示到第i位的最小花费    long long n,i,j,tmp;                        //也就知道状态转移方程为,    while(scanf("%I64d",&n)!=EOF){              //dp[i]=min(dp[i],dp[j]+sum[j+1][i]*sum[j+1][i])        map<long long,long long> mp;            //(1<=j<i),sum[i][j]为区间内的颜色种类        memset(dp,INF,sizeof(dp));              //但是复杂度为n*n,因此一定会超时        for(i=1;i<=n;i++){        scanf("%I64d",&a[i]);        pre[i]=i-1,nex[i]=i+1;        }        dp[0]=0,pre[0]=-1;        for(i=1;i<=n;i++){                      //因此用双向链表进行优化,遇到出现过的数字            if(mp[a[i]]==0)                     //直接跳过            mp[a[i]]=i;            else{                tmp=mp[a[i]];                nex[pre[tmp]]=nex[tmp];                         pre[nex[tmp]]=pre[tmp];                mp[a[i]]=i;            }            tmp=0;            for(j=pre[i];j!=-1;j=pre[j]){                tmp++;                dp[i]=min(dp[i],dp[j]+tmp*tmp);                if(tmp*tmp>i)                break;            }        }        printf("%d\n",dp[n]);    }    return 0;}

0 0