【NOIP2018复习】买礼物(DP)

 

图片

         图片

输入

输出

输入样例复制

input 1:
6 25
8 9 8 7 16 5
input 2:
30 250
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

输出样例复制

output 1:
15
output 2:
6509431

说明

 

题解:设f[i,j]表示处理i~n,用了代价j 的方案数。
              将礼物从小到大排序,枚举每一件礼物,强制使该礼物为最小不能买的礼物
              则小于该礼物的全部都要强制购买,剩余rest 钱
              则对于第i个礼物的答案为sigma(f[i+1,max(0,rest-a[i]+1)~rest]) 即用的钱要使剩下的钱<a[i],且第i个无法购买,所以是i+1
             注意初值
             

const

  maxn=1001;

  p=10000007;

var

  f:array[0..maxn,0..maxn]of longint;

  c:array[0..maxn]of longint;

  n,m,i,j,min,kk,rest,ans,flag:longint;

procedure qsort(l,r:longint);

var

  i,j,key:longint;

begin

  if l>r then exit;

  i:=l;j:=r;

  key:=c[(l+r)div 2];

  repeat

    while c[i]<key do inc(i);

    while c[j]>key do dec(j);

    if i<=j then

    begin

      c[0]:=c[i];c[i]:=c[j];c[j]:=c[0];

      inc(i);dec(j);

    end;

  until i>j;

  qsort(i,r);

  qsort(l,j);

end;

function max(a,b:longint):longint;

begin

  if a>b then exit(a) else exit(b);

end;

procedure init;

var

  i,sum:longint;

begin

  readln(n,m);

  sum:=0;

  for i:=1 to n do

  begin

    read(c[i]);

    sum:=sum+c[i];

  end;

  if sum<=m then flag:=1;

  qsort(1,n);

  f[n,c[n]]:=1;

  f[n,0]:=1;

end;

begin

  init;

  if flag=1 then

  begin

    writeln(1);

    halt; 

  end;

  for i:=n downto 1 do

    for j:=0 to m do

    begin

      if (j>=c[i]) then f[i,j]:=(f[i,j]+f[i+1,j-c[i]])mod p;

      f[i,j]:=(f[i,j]+f[i+1,j])mod p;

    end;

  for kk:=1 to n  do

  begin

    rest:=m;

    for i:=1 to kk-1 do

      rest:=rest-c[i];

    if rest<0 then break;

    min:=c[kk];

    for i:=max(rest-c[kk]+1,0) to rest do

      ans:=(ans+f[kk+1,i])mod p;

  end;

  writeln(ans);

end.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值