题目大意:有长度为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
原文:http://blog.csdn.net/wyfcyx_forever/article/details/39471877