【刷题】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;
}
posted @ 2018-08-22 14:40  HYJ_cnyali  阅读(131)  评论(0编辑  收藏  举报