P3019 [JZOJ]序列和

\(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.
posted @ 2019-03-23 15:58  _ARFA  阅读(147)  评论(0编辑  收藏  举报