解题报告 比赛
2011-08-08 14:12
225 查看
[/b]
1. [/b]题目[/b]
比赛([/b]Pk.pas/c/cpp[/b])[/b][/b]
题目描述[/b][/b]
新兵们一般在部队没什么娱乐活动,而且还老有个警官在旁边即即歪歪,所以他们总要找个法子发一下怒气,所以有时候两个不同营的新兵就喜欢一起打架。。。。。。[/b] A[/b]营和[/b]B[/b]营就是典型的例子。而且他们破坏力很大,常常把操场打得这里坑一块那里坑一块,警官很头疼,因为都要他掏腰包。。。。。。[/b][/b]
[/b]为了减少损失,他决定每隔一段时间由他自己组织搞次比赛(打架)。[/b][/b]
[/b]比赛开始时两个营新兵排成两个队,每个士兵有一个破坏值,然后由警官来安排比赛的人,分任意次来[/b]PK[/b],可以是单挑,群挑,或者是单挑群(呵呵,警官只在乎修整费用最少)具体规则如下:[/b][/b]
从后往前,每次从A营选出连续k1(k1>0)个人,从B营选出连续k2(k2>0)个人进行pk。那么这次破坏导致操场的修整费用为 (S1-K1)*(S2-K2)。比赛直到两个队伍都为空时结束。而这次比赛的总修整费用就为每次PK修整费用的和。[/b]
警官拜托你的是使这次比赛的费用最小。[/b]
[/b]
输入数据[/b][/b]
[/b]第一行两个正整数L1,L2分别表示两营的人数;[/b]
第二行L1个正整数,描述A 营每个人的破坏值[/b]
第三行L2个正整数,描述B 营每个人的破坏值[/b]
1<=L1,L2<=2000[/b]
输出数据[/b][/b]
一个正整数表示操场的最小修整费用[/b]
[/b]
[/b]
样例输入[/b][/b]
3 2[/b]
1 2 3[/b]
1 2[/b]
样例输出[/b][/b]
2[/b]
[/b]
2. [/b]题目实质[/b]
动规求最优解。(废话)[/b]
3. [/b]算法[/b]
地球人都能看出来是动规,问题是,方程怎么写?[/b]
第一种:[/b]
f[i,j] [/b]代表消去序列A1[/b]的i->l1[/b],序列A2[/b]的j->l2[/b],[/b]
设A1[i]+A1[i+1]+[/b]……+A1[l1]=Si;A2[j]+A2[j+1]+[/b]……+A2[l2]=Tj ;[/b]则状态转移方程为: f[i,j]:=min{ f[p,q]+(Si-Sp-p+i)*(Tj-Tq-q+j) | (i<p<=l1+1,j<q<=l2+1) }[/b]
初始条件为 f[l1+1,l2+1]=0 ;[/b]
但这样是 O(L^4) [/b]。[/b]
观察(S1-K1)*(S2-K2)[/b]的(S1-K1)[/b]可以写成[(A1[1]-1)+(A1[2]-1)+[/b]……+(A1[K1]-1)],(S2-K2) [/b]类似。[/b]
所以我们可以在读入时就把A1 [/b],A2 [/b]的所有数全部减 1 [/b],计算时直接 S1*S2[/b]。[/b]
假设 S1*S2 [/b]的 S1 [/b]是 A1 [/b]序列中两个或两个以上元素的和, S2 [/b]类似。那么我们可以把 S1 [/b]拆成两个和 S11 [/b], S12 [/b];把 S2 [/b]拆成两个和 S21 [/b], S22 [/b]。则[/b]
S1*S2=(S11+S12)*(S21+S22)=S11*S21+S12*S21+S11*S22+S12*S22>S11*S21+S12*S22 ;[/b]
[/b]可见把它们分开消去更优。所以要这样一直拆分下去,直到某个和 S [/b]为一个元素的和。所以每次都在 A1[/b],A2 [/b]中选择某一序列的一个元素跟另外一个序列的一段(或一个)消去。[/b]
那么状态转移方程就变成了:[/b]
f[i,j]:=min{ f[i+1,q]+A1[i]*(Tj-Tq) | (j<q<=l2+1) [/b]
f[p,j+1]+(Si-Sp)*A2[j] | (i<p<=l1+1) }[/b]
[/b]这样为 O(L^3) [/b]。[/b]
假设A1[i][/b]与A2[/b]序列的一段 x->(y-1) [/b]一起消去。如下图,[/b]
A1[i]: [/b]□[/b]
i[/b]
A2[x]->A2[(y-1)]: [/b]□ [/b]□ [/b]□ [/b]□ [/b]…… [/b]□ [/b]□[/b]
x x+1 x+2 …… y-2 y-1[/b]
这个表示为 f[i,x]=f[i+1[/b],y]+A1[i]*(Tx-Ty)[/b]。[/b]
显然可以看做是 A1[i] [/b]跟 A2[x+1]->A2[y-1] [/b]一起消去然后A1[i][/b]再跟A2[x][/b]一起消去,而前者为 f[i,x+1] , [/b]后者为 A1[i]*A2[x] [/b];[/b]
[/b]所以还可以表示为 f[i,x]=f[i,x+1]+A1[i]*A2[x];[/b]
那么状态转移方程就变成了:[/b]
f[i,j]:=min{ f[i+1,j]+A1[i]*A2[j] //A1[/b]序列的i[/b]与A2[/b]序列从j[/b]开始的一段一起消去 [/b]
f[i,j+1]+A1[i]*A2[j] //A1[/b]序列从i[/b]开始的一段与A2[/b]序列的j[/b]一起消去[/b]
f[i+1,j+1]+A1[i]*A2[j] } //A1[/b]序列的i[/b]与A2[/b]序列的j[/b]一起消去[/b]
这样就是O(L^2)[/b]的了。[/b]
[/b]
4. [/b]注意事项[/b]
注意 f [/b]数组的初值![/b]
5. [/b]程序代码[/b]
SueMiller [/b](Pascal[/b])[/b]
var l1,l2:integer;[/b]
a1,a2:array[0..2010]of longint;[/b]
i,j:integer;[/b]
f:array[0..2010,0..2010]of longint;[/b]
[/b]
function min(a,b:longint):longint;[/b]
begin[/b]
if a<b then exit(a) else exit(b);[/b]
end;[/b]
[/b]
begin[/b]
assign(input,'Pk.in');reset(input);[/b]
assign(output,'Pk.out');rewrite(output);[/b]
[/b]
readln(l1,l2);[/b]
for i:=1 to l1 do begin read(a1[i]);dec(a1[i]);end;[/b]
for i:=1 to l2 do begin read(a2[i]);dec(a2[i]);end;[/b]
[/b]
filldword(f,sizeof(f)>>2,maxlongint);[/b]
f[l1+1,l2+1]:=0;[/b]
for i:=l1 downto 1 do[/b]
for j:=l2 downto 1 do[/b]
begin[/b]
f[i,j]:=min(min(f[i+1,j],f[i,j+1]),f[i+1,j+1])+a1[i]*a2[j];[/b]
end;[/b]
[/b]
writeln(f[1,1]);[/b]
[/b]
close(input);close(output);[/b]
end.[/b]
[/b]
[/b]
1. [/b]题目[/b]
比赛([/b]Pk.pas/c/cpp[/b])[/b][/b]
题目描述[/b][/b]
新兵们一般在部队没什么娱乐活动,而且还老有个警官在旁边即即歪歪,所以他们总要找个法子发一下怒气,所以有时候两个不同营的新兵就喜欢一起打架。。。。。。[/b] A[/b]营和[/b]B[/b]营就是典型的例子。而且他们破坏力很大,常常把操场打得这里坑一块那里坑一块,警官很头疼,因为都要他掏腰包。。。。。。[/b][/b]
[/b]为了减少损失,他决定每隔一段时间由他自己组织搞次比赛(打架)。[/b][/b]
[/b]比赛开始时两个营新兵排成两个队,每个士兵有一个破坏值,然后由警官来安排比赛的人,分任意次来[/b]PK[/b],可以是单挑,群挑,或者是单挑群(呵呵,警官只在乎修整费用最少)具体规则如下:[/b][/b]
从后往前,每次从A营选出连续k1(k1>0)个人,从B营选出连续k2(k2>0)个人进行pk。那么这次破坏导致操场的修整费用为 (S1-K1)*(S2-K2)。比赛直到两个队伍都为空时结束。而这次比赛的总修整费用就为每次PK修整费用的和。[/b]
警官拜托你的是使这次比赛的费用最小。[/b]
[/b]
输入数据[/b][/b]
[/b]第一行两个正整数L1,L2分别表示两营的人数;[/b]
第二行L1个正整数,描述A 营每个人的破坏值[/b]
第三行L2个正整数,描述B 营每个人的破坏值[/b]
1<=L1,L2<=2000[/b]
输出数据[/b][/b]
一个正整数表示操场的最小修整费用[/b]
[/b]
[/b]
样例输入[/b][/b]
3 2[/b]
1 2 3[/b]
1 2[/b]
样例输出[/b][/b]
2[/b]
[/b]
2. [/b]题目实质[/b]
动规求最优解。(废话)[/b]
3. [/b]算法[/b]
地球人都能看出来是动规,问题是,方程怎么写?[/b]
第一种:[/b]
f[i,j] [/b]代表消去序列A1[/b]的i->l1[/b],序列A2[/b]的j->l2[/b],[/b]
设A1[i]+A1[i+1]+[/b]……+A1[l1]=Si;A2[j]+A2[j+1]+[/b]……+A2[l2]=Tj ;[/b]则状态转移方程为: f[i,j]:=min{ f[p,q]+(Si-Sp-p+i)*(Tj-Tq-q+j) | (i<p<=l1+1,j<q<=l2+1) }[/b]
初始条件为 f[l1+1,l2+1]=0 ;[/b]
但这样是 O(L^4) [/b]。[/b]
观察(S1-K1)*(S2-K2)[/b]的(S1-K1)[/b]可以写成[(A1[1]-1)+(A1[2]-1)+[/b]……+(A1[K1]-1)],(S2-K2) [/b]类似。[/b]
所以我们可以在读入时就把A1 [/b],A2 [/b]的所有数全部减 1 [/b],计算时直接 S1*S2[/b]。[/b]
假设 S1*S2 [/b]的 S1 [/b]是 A1 [/b]序列中两个或两个以上元素的和, S2 [/b]类似。那么我们可以把 S1 [/b]拆成两个和 S11 [/b], S12 [/b];把 S2 [/b]拆成两个和 S21 [/b], S22 [/b]。则[/b]
S1*S2=(S11+S12)*(S21+S22)=S11*S21+S12*S21+S11*S22+S12*S22>S11*S21+S12*S22 ;[/b]
[/b]可见把它们分开消去更优。所以要这样一直拆分下去,直到某个和 S [/b]为一个元素的和。所以每次都在 A1[/b],A2 [/b]中选择某一序列的一个元素跟另外一个序列的一段(或一个)消去。[/b]
那么状态转移方程就变成了:[/b]
f[i,j]:=min{ f[i+1,q]+A1[i]*(Tj-Tq) | (j<q<=l2+1) [/b]
f[p,j+1]+(Si-Sp)*A2[j] | (i<p<=l1+1) }[/b]
[/b]这样为 O(L^3) [/b]。[/b]
假设A1[i][/b]与A2[/b]序列的一段 x->(y-1) [/b]一起消去。如下图,[/b]
A1[i]: [/b]□[/b]
i[/b]
A2[x]->A2[(y-1)]: [/b]□ [/b]□ [/b]□ [/b]□ [/b]…… [/b]□ [/b]□[/b]
x x+1 x+2 …… y-2 y-1[/b]
这个表示为 f[i,x]=f[i+1[/b],y]+A1[i]*(Tx-Ty)[/b]。[/b]
显然可以看做是 A1[i] [/b]跟 A2[x+1]->A2[y-1] [/b]一起消去然后A1[i][/b]再跟A2[x][/b]一起消去,而前者为 f[i,x+1] , [/b]后者为 A1[i]*A2[x] [/b];[/b]
[/b]所以还可以表示为 f[i,x]=f[i,x+1]+A1[i]*A2[x];[/b]
那么状态转移方程就变成了:[/b]
f[i,j]:=min{ f[i+1,j]+A1[i]*A2[j] //A1[/b]序列的i[/b]与A2[/b]序列从j[/b]开始的一段一起消去 [/b]
f[i,j+1]+A1[i]*A2[j] //A1[/b]序列从i[/b]开始的一段与A2[/b]序列的j[/b]一起消去[/b]
f[i+1,j+1]+A1[i]*A2[j] } //A1[/b]序列的i[/b]与A2[/b]序列的j[/b]一起消去[/b]
这样就是O(L^2)[/b]的了。[/b]
[/b]
4. [/b]注意事项[/b]
注意 f [/b]数组的初值![/b]
5. [/b]程序代码[/b]
SueMiller [/b](Pascal[/b])[/b]
var l1,l2:integer;[/b]
a1,a2:array[0..2010]of longint;[/b]
i,j:integer;[/b]
f:array[0..2010,0..2010]of longint;[/b]
[/b]
function min(a,b:longint):longint;[/b]
begin[/b]
if a<b then exit(a) else exit(b);[/b]
end;[/b]
[/b]
begin[/b]
assign(input,'Pk.in');reset(input);[/b]
assign(output,'Pk.out');rewrite(output);[/b]
[/b]
readln(l1,l2);[/b]
for i:=1 to l1 do begin read(a1[i]);dec(a1[i]);end;[/b]
for i:=1 to l2 do begin read(a2[i]);dec(a2[i]);end;[/b]
[/b]
filldword(f,sizeof(f)>>2,maxlongint);[/b]
f[l1+1,l2+1]:=0;[/b]
for i:=l1 downto 1 do[/b]
for j:=l2 downto 1 do[/b]
begin[/b]
f[i,j]:=min(min(f[i+1,j],f[i,j+1]),f[i+1,j+1])+a1[i]*a2[j];[/b]
end;[/b]
[/b]
writeln(f[1,1]);[/b]
[/b]
close(input);close(output);[/b]
end.[/b]
[/b]
[/b]
相关文章推荐
- 7.3模拟比赛解题报告
- 2011年"新秀杯"程序设计比赛——现场决赛参考解题报告和个人总结
- 谷歌中国算法比赛解题报告 APAC2016A
- 【比赛练习ac题】poj2253+hdu2717+poj2387+poj1258【解题报告】
- 杭州电子科技大学Online Judge 之 “确定比赛名次(ID1285)”解题报告
- 谷歌中国算法比赛解题报告 APAC2016B
- 谷歌中国算法比赛解题报告 APAC2016D
- 西南交大2011年第二次暑期集训比赛解题报告
- 谷歌中国算法比赛解题报告 APAC2017A
- 7.9模拟比赛解题报告
- 2018年全国多校算法寒假训练营练习比赛(第二场)解题报告
- 第36届acm_icpc 北京赛区,网络赛解题报告 & 比赛log
- openoj的一个小比赛(B题解题报告)
- HDU1285 确定比赛名次 解题报告--拓扑排序
- 深圳大学2012年程序设计比赛解题报告
- USACO历年比赛的数据和解题报告
- openoj的一个小比赛(G题解题报告)优先队列
- hdu 1285 确定比赛名次 解题报告
- 宁波比赛解题报告
- USACO历年比赛的数据和解题报告