Description
ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN。 由于她的疏忽, 第 i 个物品丢失了。 “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢?” -- 这是经典的问题了。她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。
Input
第1行:两个整数 N (1 ≤ N ≤ 2 × 103) 和 M (1 ≤ M ≤ 2 × 103),物品的数量和最大的容积。
第2行: N 个整数 W1, W2, ..., WN, 物品的体积。
Output
一个 N × M 的矩阵, Count(i, x) 的末位数字。
Sample Input
3 2
1 1 2Sample Output
11
11 21HINT
如果物品3丢失的话,只有一种方法装满容量是2的背包,即选择物品1和物品2。
Solution
首先一点,背包物品的转移顺序对答案是没有影响的
考虑二分,\(solve(l,r)\) 代表此时用 \([1,l)\) 和 \((r,n]\) 的物品将背包处理好了,需 要求 \(i\in[l,r]\) 的答案 将 \([l,r]\) 分为两段,如果要处理 \([l,mid]\) ,就用 \((mid,r]\) 的物品更新当前背包;处理 \((mid,r]\) ,就用 \([l,mid]\) 的物品去更新当前背包\(l=r\) 时,当前背包就是去掉物品 \(l\) 的答案了#include#define ui unsigned int#define ll long long#define db double#define ld long double#define ull unsigned long longconst int MAXN=2000+10;int n,m,w[MAXN],f[20][MAXN];template inline void read(T &x){ T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w;}template inline void write(T x,char ch='\0'){ if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(ch!='\0')putchar(ch);}template inline void chkmin(T &x,T y){x=(y inline void chkmax(T &x,T y){x=(y>x?y:x);}template inline T min(T x,T y){return x inline T max(T x,T y){return x>y?x:y;}inline void solve(int dep,int l,int r){ if(l==r) { for(register int i=1;i<=m;++i)write(f[dep][i]%10);puts(""); return ; } int Mid=(l+r)>>1; for(register int i=0;i<=m;++i)f[dep+1][i]=f[dep][i]; for(register int i=Mid+1;i<=r;++i) for(register int j=m;j>=w[i];--j)(f[dep+1][j]+=f[dep+1][j-w[i]])%=10; solve(dep+1,l,Mid); for(register int i=0;i<=m;++i)f[dep+1][i]=f[dep][i]; for(register int i=l;i<=Mid;++i) for(register int j=m;j>=w[i];--j)(f[dep+1][j]+=f[dep+1][j-w[i]])%=10; solve(dep+1,Mid+1,r);}int main(){ read(n);read(m); for(register int i=1;i<=n;++i)read(w[i]); f[0][0]=1;solve(0,1,n); return 0;}