解题报告 QUE
即 usaco Mar 09 Cleaning Up
【转】
题意Overview:
有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000。 现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k。那总的不河蟹度就是所有段的不河蟹度的总和。
题解Solution:
直观就会有一个N^2的DP。
首先是如果把它们切成N段的话,答案上界是N。所以如果某[i, j]段kN−− ,这肯定不是最优解的一部分,可以break。
用diff[i, j]表示[i, j]间不同的数的数目。
决策到f[i]时,若k < j, 且有diff[k, i] == diff[j, i],那么直接skip掉j直接跳到k。
不要忽略一个很显然的东西:有diff[k, i] == diff[j, i],就必然有diff[k, i'] == diff[k, i']。(i < i')。也就是f[k -1]总是比f[j -1]优的T_T。
const MaxN = 40001; var idx, appear, a, f: array[0..MaxN] of longint; i, j, k, n, m, lim, orz: longint; function min(a, b: longint): longint; begin if a < b then exit(a) else exit(b); end; begin assign(input, '1584.in'); reset(input); assign(output, '1584.out'); rewrite(output); read(n, m); for i:= 1 to n do begin read(a[i]); appear[i]:= -1; end; lim:= trunc(sqrt(n)); idx[0]:= 1; for i:= 1 to n do begin k:= appear[a[i]]; j:= 0; while (j <= lim) and (idx[j] - 1 <> k) do inc(j); dec(j); for j:= j downto 0 do idx[j + 1]:= idx[j]; f[i]:= i; for j:= 1 to lim do begin if idx[j] = 0 then break; f[i]:= min(f[i], f[idx[j] – 1] + sqr(j)); end; inc(idx[0]); appear[a[i]]:= i; end; writeln(f[n]); close(input); close(output); end.