题目描述
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.

相关文章: