BZOJ1584 USACO 2009 Mar Gold 2.Cleaning Up

题目大意:有长度为N的颜色段,共有m种颜色,要将其划分成若干段,每一段的费用为这一段的不同颜色的数目的平方。求最小总费用。


Sol:

首先我们注意到答案不超过n,因为我们显然可以将每一个划分为一段,答案为n.

于是每一段的颜色总数不超过sqrt(n).

因此我们维护最后出现的sqrt(n)种颜色最后出现的位置,进行转移。

总的时间复杂度为O(n*sqrt(n)).


Code:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
#define N 40010
#define M 40010
int col[N], dp[N], seq[210], now[210];
 
#define sqr(x) ((x)*(x))
 
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
     
    register int i, j;
    for(i = 1; i <= n; ++i)
        scanf("%d", &col[i]);
     
    int lim = (int)sqrt(n);
    int nowlen = 0;
     
    int ins;
    for(i = 1; i <= n; ++i) {
        dp[i] = i;
        ins = 0;
        for(j = 1; j <= nowlen; ++j)
            if (seq[j] == col[i]) {
                ins = j;
                break;
            }
        if (!ins) {
            if (nowlen != lim) {
                seq[++nowlen] = col[i];
                now[nowlen] = i;
            }
            else {
                for(j = 1; j < nowlen; ++j)
                    seq[j] = seq[j + 1], now[j] = now[j + 1];
                seq[nowlen] = col[i], now[nowlen] = i;
            }
        }
        else {
            for(j = ins; j < nowlen; ++j)
                seq[j] = seq[j + 1], now[j] = now[j + 1];
            seq[nowlen] = col[i], now[nowlen] = i;
        }
        for(j = nowlen; j >= 2; --j)
            dp[i] = min(dp[i], dp[now[j - 1]] + sqr(nowlen + 1 - j));
    }
     
    printf("%d", dp[n]);
     
    return 0;
}


你可能感兴趣的:(BZOJ1584 USACO 2009 Mar Gold 2.Cleaning Up)