自爆魂

博客园 首页 新随笔 联系 订阅 管理

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

有一段序列,涂连续一段子序列的代价为该子序列出现不同数字个数的平方,求最小代价涂完整个序列。

ai有10^9,所以先进行离散化

复杂度有n^2,需要剪枝,就是如果答案大于了dp[n]就不用往后继续转移了,这样复杂度就变成了O(n√n)

vector用的姿势不对会T

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include<set>
#include <iostream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define clr0(x) memset(x,0,sizeof(x))
typedef long long LL;
const int INF = 1000000009;
int n,r,dp[50005];
struct node{
    int rank,v,i;
}p[50005];
bool vis[50005];
bool cmp(node a,node b)
{
    return a.v < b.v;
}
bool _cmp(node a,node b)
{
    return a.i < b.i;
}
int main() {
    while(~RD(n)){
        for(int i = 1;i <= n;++i){
            RD(p[i].v);
            p[i].i = i;
        }
        sort(p+1,p+n+1,cmp);
        p[1].rank = r = 0;
        for(int i = 2;i <= n;++i){
            if(p[i].v != p[i-1].v)
                p[i].rank = ++r;
            else
                p[i].rank = r;
        }
        sort(p+1,p+n+1,_cmp);

        clr0(vis);
        vector <int> vt;
        for(int i = 0;i <= n;++i){
            dp[i] = i;
        }
        for(int j = 0;j < n;++j){
            for(int i = j+1;i <= n;++i){
                if(!vis[ p[i].rank ])
                    vis[ p[i].rank ] = 1,vt.push_back(p[i].rank);
                int tmp = dp[j] + vt.size()*vt.size();
                if(tmp > dp[n]) break;
                dp[i] = min(dp[i],tmp);
            }
            for(int i = 0;i < vt.size();i++)
                vis[vt[i]] = 0;
            vt.clear();
        }
        cout<<dp[n]<<endl;
    }
    return 0;
}


posted on 2014-10-15 19:31  自爆魂  阅读(128)  评论(0编辑  收藏  举报