//本题的思路是,从大到小排序一遍,然后超过每月零花钱的直接加这种钱的数目,否则不行的话就从小的往大的凑,直到凑出一个能达到c的组合,然后ans+1 program P1032; type atp=record v,b:longint; end; var n,c,ans:longint; a:array [1..20] of atp; procedure swap(var x,y:atp); var t:atp; begin t:=x; x:=y; y:=t; end; procedure qsort(l,r:longint); var i,j,m:longint; begin i:=l; j:=r; m:=a[(l+r) shr 1].v; repeat while a[i].v>m do inc(i); while a[j].v<m do dec(j); if i<=j then begin swap(a[i],a[j]); inc(i); dec(j); end; until i>j; if i<r then qsort(i,r); if l<j then qsort(l,j); end; procedure init; var i:longint; begin ans:=0; readln(n,c); for i:=1 to n do readln(a[i].v,a[i].b); qsort(1,n); end; procedure main; var i,temp,rest:longint; begin temp:=0; for i:=1 to n do begin if a[i].v>=c then begin inc(ans,a[i].b); inc(temp);//记录一下比c大的钱用了多少种,这类的钱直接加上它的数目,因为它不需要和任何一种钱配对,否则就会造成浪费。 end; end; //注意temp是我们最后记录的一个不用凑的钱,因此从temp+1开始循环 repeat rest:=c; for i:=temp+1 to n do begin while (rest-a[i].v>=0) and (a[i].b>0) do//先单一的用大的钱去凑看能凑出多少种组合 begin dec(rest,a[i].v); dec(a[i].b); end; end; for i:=n downto temp+1 do begin while (rest>0) and (a[i].b>0) do//然后通过判断rest是否大于0,a[i].b是否大于0看能否继续凑,如果rest=0,说明在之前的凑法中用大钱已经能够正好凑出C,这时就不需要再凑了,以避免浪费。而a[i].b大于0则是为了保证当前选择的小钱还有,这样的话才能继续凑。 begin dec(rest,a[i].v); dec(a[i].b); end; end; if rest<=0 then inc(ans);//如果已经凑够了就是一种组合。这样的话ans+1。 until rest>0;//rest能够大于0,说明无论如何也凑不出来了,这样我们的计算就结束了。 end; begin assign(input,'P1032.in'); reset(input); assign(output,'P1032.out'); rewrite(output); init; main; writeln(ans); close(input); close(output); end.