que
Que
【Description】
给出一个n个数组成的序列,这n个数的值∈[1,m],对于一段区间,如果其中值的种类数为K,那么我们称这段区间的价值为K2。请将序列进行合适的划分,使得总价值最小。总价值为各段价值之和。
【Input Format】
第一行两个数n,m。
接下来n行,每行一个数,表示序列中每个数的值。
【Output Format】
一个数,表示总价值。
【Sample Input】
13 4
1
2
1
3
2
2
3
4
3
4
3
1
4
【Sample Output】
11
分析:这道题的解法其实挺巧妙的。
尤其是下面程序中的对q,p数组的维护部分,
采用动态更新的方法,
我也是单步执行了好久才看出一点端倪。。。
(注:q[i]表示从当前点开始向左种数为i的最长区间的左端点位置,
p[i]表示当前点前i这个值出现的最靠右位置,
这两个数组互相动态更新)
program que;
var
q:array[0..250]of longint;
a,p,f:array[0..40005]of longint;
tmp,tail,i,j,k,n,m,len:longint;
vv:boolean;
function min(x,y:longint):longint;
begin
if x<y then exit(x);
exit(y);
end;
begin
assign(input,'que.in');
reset(input);
assign(output,'que.out');
rewrite(output);
readln(n,m);
for i:=1 to n do
begin
read(a[i]);
f[i]:=maxlongint>>1;
end;
len:=trunc(sqrt(n));
f[0]:=0;
tail:=1;
q[1]:=1;
f[1]:=1;
p[a[1]]:=1;
for i:=2 to n do
begin
k:=i;
for j:=1 to tail do
if q[j]>p[a[i]] then
begin
tmp:=q[j];
q[j]:=k;
k:=tmp;
end else break;
if (tail<len)and(q[tail]>p[a[i]]) then
begin
inc(tail);
q[tail]:=k;
end;
p[a[i]]:=i;
for j:=1 to tail do
f[i]:=min(f[i],f[q[j]-1]+j*j);
end;
writeln(f[n]);
close(input);
close(output);
end.
浙公网安备 33010602011771号