2018年10月27提高組 T1 Gift
阿新 • • 發佈:2018-12-17
大意
給定個物品,每個物品只能選一次,求出在空間不超過且不能再選任何一個物品時的方案數對取模
思路
發現這玩意兒很像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);//輸出
}