如要转载,请标明出处!
题目描述
新兵们一般在部队没什么娱乐活动,而且还老有个警官在旁边即即歪歪,所以他们总要找个法子发一下怒气,所以有时候两个不同营的新兵就喜欢一起打架。。。。。。 A营和B营就是典型的例子。而且他们破坏力很大,常常把操场打得这里坑一块那里坑一块,警官很头疼,因为都要他掏腰包。。。。。。
为了减少损失,他决定每隔一段时间由他自己组织搞次比赛(打架)。
比赛开始时两个营新兵排成两个队,每个士兵有一个破坏值,然后由警官来安排比赛的人,分任意次来PK,可以是单挑,群挑,或者是单挑群(呵呵,警官只在乎修整费用最少)具体规则如下:
从后往前,每次从A营选出连续k1(k1>0)个人,从B营选出连续k2(k2>0)个人进行pk。那么这次破坏导致操场的修整费用为 (S1-K1)*(S2-K2)。比赛直到两个队伍都为空时结束。而这次比赛的总修整费用就为每次PK修整费用的和。
警官拜托你的是使这次比赛的费用最小。
输入数据
第一行两个正整数L1,L2分别表示两营的人数;
第二行L1个正整数,描述A 营每个人的破坏值
第三行L2个正整数,描述B 营每个人的破坏值
1<=L1,L2<=2000
输出数据
一个正整数表示操场的最小修整费用
样例输入
3 2
1 2 3
1 2
样例输出
2
分析:
本题显然满足动规条件。
可以很容易的想到,用一个四维的数组存储状态,f[i,j,p,q],表示在第一个队伍中取出p个,在第二个队伍中取出q个的最优值,时间按复杂度为O(L^4),显然会超时。
优化:
数据的读入
注意到(S1-K1)*(S2-K2)的(S1-K1)可以写成[(A1[1]-1)+(A1[2]-1)+……+(A1[K1]-1)],(S2-K2)类似,因此我们在数据的读入时就可以直接让a[i]减一。此时破坏值=s1*s2
有关状态和方程
各取两队中的>=2个人进行决斗,其破坏值s1和s2都可以拆分成两部分s1*s2=(s11+s12)*s(21+s22)<s11*s21+s12*s22(让s11和s21打,s12和s22打),由此我们可以得出结论,一起打不如分开打。一直拆分下去,直到某个和S为一个元素的和,可以使答案越来越优。
所以我们可以得出方程f[i,j]:=min{ f[i+1,q]+A1[i]*(Tj-Tq) | (j<q<=l2+1)
f[p,j+1]+(Si-Sp)*A2[j] | (i<p<=l1+1)
只需要三层的循环:i,j和p(q和p同时枚举,在同以优先级),O(L^3)
进一步优化:
对于其中一个方程f[i,j]:=f[i-1,p]*Σb[p+1]+...+b[j]*a[i](第一队中的1人和j中的j-p人打)。
f[i,j]:=f[i-1,p]*Σb[p+1]+...+b[j]*a[i]
=f[i-1,p]*Σb[p+1]+...+b[j-1]*a[i]+b[j]*a[i];
=f[i,j-1]+b[j]*a[i]
化简到这里,我们发现状态中的p(q同理)已经被化掉,现在的时间复杂度O(L^2)
现在考虑:为什么f[i,j]和f[i,j-1]取最优值的p为什么是相同的呢?
当f[i,j-1]取到最优时,它与f[i,j]的区别是,和i队列中最后一个人pk的人的个数,显然,f[i,j]只比f[i,j-1]多了一个常数,所以f[i,j]与f[i,j-1]取最优值的时候p相同
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 program pk;
2 var f:array[0..2000,0..2000] of longint;
3 a,b:array[1..2000] of longint;
4 n1,n2:longint;
5 i,j:longint;
6 procedure init;
7 begin
8 readln(n1,n2);
9 for i:=1to n1 do
10 begin
11 read(a[i]);
12 dec(a[i]);
13 end;
14 for i:=1to n2 do
15 begin
16 read(b[i]);
17 dec(b[i]);
18 end;
19 end;
20 function min(x,y,z:longint):longint;
21 begin
22 min:=x;
23 if y<min then min:=y;
24 if z<min then min:=z;
25 end;
26 procedure work;
27 begin
28 fillchar(f,sizeof(f),127);
29 f[0,0]:=0;
30 for i:=1to n1 do
31 for j:=1to n2 do
32 f[i,j]:=min(f[i-1,j],f[i,j-1],f[i-1,j-1])+a[i]*b[j];
33 end;
34 begin
35 init;
36 work;
37 writeln(f[n1,n2]);
38 end.