考状态的dp
我的方法可能比较奇怪
设f[i,j]表示第i个月解决j个问题可以最多解决到第几个问题
容易知道,答案(月份)不会超过2n+1;
f[i,j]=max(f[i-1,k]+j)
复杂度为O(n^3)
代码如下
1 var f:array[0..1000,0..500] of longint; 2 b,a,sa,sb:array[0..500] of longint; 3 p,y,q,i,j,k,n,m:longint; 4 function max(a,b:longint):longint; 5 begin 6 if a>b then exit(a) else exit(b); 7 end; 8 9 begin 10 readln(m,n); 11 for i:=1 to n do 12 begin 13 readln(b[i],a[i]); 14 sa[i]:=sa[i-1]+a[i]; 15 sb[i]:=sb[i-1]+b[i]; 16 end; 17 f[1,0]:=0; 18 i:=1; 19 while i<=2*n+1 do 20 begin 21 inc(i); 22 f[i,0]:=f[i-1,0]; 23 for j:=1 to n do 24 begin 25 if f[i-1,j]=0 then break; 26 f[i,0]:=max(f[i,0],f[i-1,j]); 27 end; 28 for j:=1 to n do 29 begin 30 for k:=0 to n do 31 begin 32 if (f[i-1,k]=0) and (k<>0) then break; //后面的状态不存在,直接退 33 p:=f[i-1,k]; 34 q:=f[i-1,k]+j; 35 if q>n then continue; 36 y:=f[i-1,k]-k; 37 if (sb[q]-sb[p]+sa[p]-sa[y]<=m) and (sa[q]-sa[p]<=m) then //判断是否够这个月花的 38 f[i,j]:=max(f[i,j],f[i-1,k]+j); 39 end; 40 if f[i,j]>=n then 41 begin 42 writeln(i+1); //注意付完款一定是下个月 43 halt; 44 end; 45 if f[i,j]=0 then break; 46 end; 47 end; 48 end.
话说代码有的地方可能写的比较冗杂……