hdu5009 Paint Pearls

dp

首先暴力的dp式子: f[i]=min{f[j]+num(j+1,i)}

这样是n^2的

考虑优化:

代价是一段区间不同颜色的数量,

那么如果区间的颜色数量是相同的,更新长度更长的区间一定更优

那么可以用双向链表优化一下,当一个数在之前出现过的时候,就将之前出现过的位置删除掉

其实相当于离散化了一下,只保留了对答案有用的状态

除了这个优化,可以注意到,我们肯定不会选择颜色数量超过根n的区间,因为最坏的情况下也是每个位置单独染色,代价为n

 

链表实现的小细节注意一下~ 

pre[0]设为-1

所以时间复杂度上限为 n根n

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;

const int maxn = 50010;

int n;
int f[maxn];
int a[maxn],pre[maxn],nxt[maxn];

map<int,int> mp; 

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;}

int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pre[i]=i-1;
            nxt[i]=i+1;
        }
        
        memset(f,0x3f,sizeof(f));
        f[0]=0; pre[0]=-1;
        mp.clear();
        for(int i=1;i<=n;i++){
            if(mp[a[i]]==0) mp[a[i]]=i;
            else{
                int id=mp[a[i]];
                pre[nxt[id]]=pre[id];
                nxt[pre[id]]=nxt[id];
                mp[a[i]]=i;
            }
            
            int cnt=0;
            for(int j=pre[i];j!=-1;j=pre[j]){
                ++cnt;
                if(cnt*cnt>i) break;
                f[i]=min(f[i],f[j]+cnt*cnt);
            }
        }
        printf("%d\n",f[n]);
    }

    return 0;
}

 

posted @ 2019-02-25 10:22  Tartarus_li  阅读(145)  评论(0编辑  收藏  举报