(题目描述截图自洛谷)
标签:环形DP
题解:
首先将数组开为2倍,破环成链,用f[x,i,j]表示以第x个数为第一个数,在前i个数中分出j组可以取得的最大值。用g[x,i,j]表示以第x个数为第一个数,在前i个数中分出j组可以取得的最小值。以f数组为例,那么f[x,i,j]可以由f[x,i-1,j-1] f[x,i-2,j-1] ......乘以a[x+i-1]得到。因为要保证在前i-k个数中可以分出j-1组,从而i-k>=j-1 ,得1<=k<=i-j+1。 从而得到状态转移方程:
f[x,i,j]=max{ f[x,i-k,j-1]*a[x+i-1] } (1<=k<=i-j+1)
g[x,i,j]=min{ g[x,i-k,j-1]*a[x+i-1] } (1<=k<=i-j+1)
注意要在j=1的时候加特判。
最后输出f[x,n,m]中的最大值,g[x,n,m]中的最小值(1<=x<=n)即可。
实现时的问题:
1、因为开的是3维数组,导致单调的时候不易看出变量的变化。后来干脆输出所有的f,g的值,结果在提交之前忘了把 这些用来调试的输出语句删除,导致全WA。
2、在写j(记录组数状态)的循环时,一开始直接写了:
for j:=1 to i do
结果WA掉两个点。后来一方觉得改不出什么错就改成:
for j:=1 to min(i,m) do
就过了。虽然觉得这似乎无关紧要,但是加上之后还是要严谨加上省时一些。
代码实现:
最终的代码实现如下:
Uses math;
Var n,m,i,j,k,x,l,b,s:longint;
a:array[1..100]of longint;
q:array[1..100,1..100]of longint;
f,g:array[1..50,0..100,0..10]of longint;
function mx(l,r:longint):longint;
Var i,j:longint;
Begin
mx:=0;
for i:=l to r do inc(mx,a[i]);
if mx>0 then exit(mx mod 10)
else mx:=(100000+mx)mod 10;
End;
Begin
readln(n,m);
for i:=1 to n do readln(a[i]);
for i:=n+1 to 2*n do a[i]:=a[i-n];
for i:=1 to 50 do
for j:=0 to 100 do
for k:=0 to 10 do
Begin f[i,j,k]:=1;
if k=0 then g[i,j,k]:=1
else g[i,j,k]:=maxlongint; End;
for x:=1 to n do
for i:=1 to n do
for j:=1 to min(i,m) do
for k:=i-j+1 downto 1 do
Begin if j>1 then
Begin f[x,i,j]:=max(f[x,i,j],f[x,i-k,j-1]*mx(x+i-k,x+i-1));
if g[x,i-k,j-1]=maxlongint then g[x,i,j]:=g[x,i,j]
else g[x,i,j]:=min(g[x,i,j],g[x,i-k,j-1]*mx(x+i-k,x+i-1));
End;
if j=1 then
Begin f[x,i,j]:=mx(x,x+i-1);
g[x,i,j]:=mx(x,x+i-1);
End;
End;
b:=0; s:=maxlongint;
for x:=1 to n do
Begin b:=max(b,f[x,n,m]); s:=min(s,g[x,n,m]); End;
writeln(s);
writeln(b);
End.