从小到大排序后
我们可以设一个方案中,消耗的魔法长这个样子:从1开始选连续的一段较小的魔法,然后选若干个分散的较大的魔法。
所以我们就需要枚举,第一个不选的魔法,在它前面的一段连续的较小的魔法,在此次枚举中,都需要被选进。而对于后面选的分散的较大的魔法的取法方案数,dp计数(背包计数)。
那么我们就拿样例来说明一下:
5 14
3 6 2 1 8
排序后:
5 14
1 2 3 6 8
当我们设8是第一个不选的较小魔法后,8后面的较大魔法就进行一次dp计数。
当我们设6是第一个不选的较小魔法后,6后面的较大魔法就进行一次dp计数。
当我们设3是第一个不选的较小魔法后,3后面的较大魔法就进行一次dp计数。
…
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e3+5;
int n,m,ans;
int a[N],sum[N],f[N];
signed main(){
scanf("%lld%lld",&n,&m);
for (register int i=1; i<=n; ++i) scanf("%lld",&a[i]);
sort(a+1,a+n+1);
for (register int i=1; i<=n; ++i) sum[i]=sum[i-1]+a[i];
f[0]=1;
for (register int i=n; i>=1; --i)
{
if (sum[i-1]<=m)
for (register int j=max(0ll,m-sum[i]+1); j<=m-sum[i-1]; ++j) ans+=f[j];
for (register int j=m; j>=a[i]; --j) f[j]+=f[j-a[i]];
}
printf("%lld\n",ans);
return 0;
}