牛客 能量水晶

从小到大排序后
我们可以设一个方案中,消耗的魔法长这个样子:从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];
		//当最小的不选的数为6时,我们发现,只要再在[3,8]内选任意魔法即可
		//后面至少要选总大小为 max(0,m-sum[i]+1)的魔法数,不然6就可以被选进去了
		//后面最多能选的魔法数为:m-sum[i-1],即还剩下的空间 
		for (register int j=m; j>=a[i]; --j) f[j]+=f[j-a[i]];	
	}
	printf("%lld\n",ans);
return 0;
}

猜你喜欢

转载自blog.csdn.net/Dove_xyh/article/details/108414280
今日推荐