题目描述
NaCN_JDavidQ要在下个月交给老师n篇论文,论文的内容可以从m个课题中选择。由于课题数有限,NaCN_JDavidQ不得不重复选择一些课题。完成不同课题的论文所花的时间不同。具体地说,对于某个课题i,若NaCN_JDavidQ计划一共写x篇论文,则完成该课题的论文总共需要花费Ai*x^Bi个单位时间(系数Ai和指数Bi均为正整数)。给定与每一个课题相对应的Ai和Bi的值,请帮助NaCN_JDavidQ计算出如何选择论文的课题使得他可以花费最少的时间完成这n篇论文。
输入格式
第一行有两个用空格隔开的正整数n和m,分别代表需要完成的论文数和可供选择的课题数。
以下m行每行有两个用空格隔开的正整数。其中,第i行的两个数分别代表与第i个课题相对应的时间系数Ai和指数Bi。
对于30%的数据,n<=10,m<=5;
对于100%的数据,n<=200,m<=20,Ai<=100,Bi<=5。
输出格式
输出完成n篇论文所需要耗费的最少时间。
样例输入
10 3
2 1
1 2
2 1
样例输出
19
//------------------------------------------------------------------------------------------
分析:f[i,j]表示前i篇论文,选了j个课题,花费的最少时间.
首先预处理出t[i,j]表示第i个课题选j篇花费的时间.
转移无非是考虑第i篇论文选1~j中的哪一个课题.
但这时候遇到一个麻烦,新添加的课题我们并不知道之前选了几次.
所以还需要一个数组d[i,j,k]表示f[i,j]状态下,第k个课题选了几篇.
这样转移就方便了.具体见代码.
code:
const oo=10000000000000000;
var t:array[0..21,0..201] of int64;
f:array[0..201,0..21] of int64;
d:array[0..201,0..21,0..21] of longint;
a,b:array[0..21] of longint;
n,m,i,j,k,p:longint;
minx:int64;
function calc(i,j:longint):int64;
var o:longint;
begin
calc:=1;
for o:=1 to b[i] do calc:=calc*j;
calc:=calc*a[i];
end;
function min(a,b:int64):int64;
begin
if a>b then exit(b); exit(a);
end;
begin
readln(n,m);
for i:=1 to m do readln(a[i],b[i]);
for i:=1 to m do
for j:=1 to n do t[i,j]:=calc(i,j);
for j:=1 to m do
for i:=1 to n do
begin
minx:=oo;
for k:=1 to j do
if minx>f[i-1,j]-t[k,d[i-1,j,k]]+t[k,d[i-1,j,k]+1] then
begin
minx:=f[i-1,j]-t[k,d[i-1,j,k]]+t[k,d[i-1,j,k]+1];
p:=k;
end;
f[i,j]:=minx;
d[i,j]:=d[i-1,j];
d[i,j,p]:=d[i,j,p]+1;
end;
writeln(f[n,m]);
end.