【刷题】BZOJ 2287 【POJ Challenge】消失之物
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 2
Sample Output
11
11
21
HINT
如果物品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<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=2000+10;
int n,m,w[MAXN],f[20][MAXN];
template<typename T> 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<typename T> 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<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> 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;
}