版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/83445409
大意
给定 个物品,每个物品只能选一次,求出在空间不超过 且不能再选任何一个物品时的方案数对 取模
思路
发现这玩意儿很像01背包啊,于是就有了
然后呢,因为有不能再选任何一件物品
这个约束,所以我们先排序,保证前面的小,然后枚举不能再选的物品,接着转移,这样子的复杂度是
的,期望得分60
接着我们发现,上述算法因为每次都 一次所以时间不够,于是我们就想到了能否提前求好所有的值呢?答案是可以的。
首先每次我 时只是不能选的物品多了一个,而其他地方实际上市没有区别的,所以我们换一种表示方法
设 表示后面的 个数,还剩 点空间时的方案数,得到方程:
这样我们每次转移实际上就是 往前挪一位,就不需要再用 区转移了,时间复杂度
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ymw 10000007
using namespace std;
int a[1001],n,m,minn=2147,sum;
long long ans,f[1005][1001],now;
inline void write(long long x){if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
freopen("1.txt","r",stdin);
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;i++) scanf("%d",a+i),sum+=a[i];
if(sum<=m) return putchar(49)&0;//加在一起都没有m,那么只能全部都选
sort(a+1,a+1+n);
f[n+1][0]=1;
for(register int i=n;i>0;i--)
for(register int j=0;j<=m;j++)
{
f[i][j]=f[i+1][j];
if(j>=a[i])(f[i][j]+=f[i+1][j-a[i]])%=ymw;//动态转移
}
for(register int x=1;x<=n;x++)
{
for(register int i=0;i<a[x];i++)
if(m-i>=0) (ans+=f[x+1][m-i])%=ymw;//计算在后面x+1个数的方案数
m-=a[x];//选走这个物品,容量变少了
}
write(ans%ymw);//输出
}