题目大意:有长度为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;
}