\(N\) 个数排成一个环,请选出不超过 \(K\) 段的连续的数,段与段间不能重叠,且使得选出的数和最大。
样例 :
\(\texttt{Q:}\) 2 -1 2 -1 2 -4 1 -1 2
\(\texttt{A:}\) 7
我们要注意两个点,第一,这个是个 \(\texttt{DP}\)。其次这个是一个环。
我们设 \(f_{i,j,0/1}\) 代表在第 \(i\) 个数字中已经形成 \(j\) 个段,选不选第 \(i\) 个数字形成的最大值。首先是不选的情况,那么显然 :
\[f_{i,j,0}=\max\{f_{i-1,j,0},f_{i-1,j,1}\}\]
意思是我这个数字选和不选都不会影响 \(j\),且要求最大值所以要上一个数字选和不选的情况都要考虑。然后是选的情况 :
\[f_{i,j,1}=\max\{f_{i-1,j,1},f_{i-1,j-1,0}\}+num_i\]
首先解释一下为什么要 \(+num_i\),很显然,因为到了这个区间以后可能是负数,所以不用 \(max\{...,0\}\)。然后我们可以发现,如果上个数字选了那么现在就成了一段,段的数量不增加,\(f_{i-1,j,1}\)。如果上一个没有选,我单独成段,由 \(j-1\) 变成 \(j\),\(f_{i-1,j-1,0}\)。
环怎么搞?暴力?
其实我们可以看一个图 :
如果这是一个环,那么最前面的段和最后面的段就都是段 \(1\)。那么我们是不是只要把 \(\{2,4,6\}\) 的值求出来,用全部减去它就可以了。然后要考虑可能环的情况不是最优,所以要用不是环的情况也做一遍。
Uses math;
Const
total_1=100000 << 1;
total_2=10 << 1;
var
fuck:array[-1..total_1,-1..total_2,0..1] of longint;
num:array[-1..total_1] of longint;
i,j,k,n,m,sum,maxn,minn:longint;
begin
read(n,m); maxn:=-maxlongint; minn:=maxlongint;
for i:=1 to n do begin read(num[i]); inc(sum,num[i]); end;
for i:=1 to n do for j:=1 to m do for k:=0 to 1 do fuck[i,j,k]:=-maxlongint div 8;
fuck[1,1,1]:=num[1 ]; fuck[1,0,0]:=0;
for i:=2 to n do for j:=1 to m do
begin
fuck[i,j,0]:=max(fuck[i-1,j,0],fuck[i-1,j,1]);
fuck[i,j,1]:=max(fuck[i-1,j,1],fuck[i-1,j-1,0])+num[i];
maxn:=max(fuck[i,j,0],fuck[i,j,1]);
end;
for i:=1 to n do for j:=1 to m do for k:=0 to 1 do fuck[i,j,k]:=maxlongint div 8;
fuck[1,1,1]:=num[1]; fuck[1,0,0]:=0;
for i:=2 to n do for j:=1 to m do
begin
fuck[i,j,0]:=min(fuck[i-1,j,0],fuck[i-1,j,1]);
fuck[i,j,1]:=min(fuck[i-1,j,1],fuck[i-1,j-1,0])+num[i];
minn:=min(fuck[i,j,0],fuck[i,j,1]);
end;
writeln(max(sum-minn,maxn));
end.