题目大意
给定
n
种物品,每种物品有无限个,体积是
现在有
m
个询问,每个询问给一个背包容量
要求使用的
Vi≥L
的个数不超过
C
个。
Data Constraint
题解
假如存在最小的
Vi<L
(记为
Vmin
)且存在
x
可以在合法情况下被恰好装满,那么
所以我们的想法就比较直观了,只需要维护
Wi%Vmin
是否合法即可。
设
fi,j
表示已经用了
i
个大件物品,最小的
枚举这一次选择
Vk
来填充,那么
fi,j→fi+(Vk≥L),(j+Vk)%Vmin
,因为可能转移到之前的状态,所以这里需要SPFA来转移。
最后记
ansj=mini≤Ci=0fi,j
,对于一个询问
Wi
如果
ansWi%Vmin≤Wi
那么
Wi
就是有解的,否则无解。
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 50 + 10
#define M 10000 + 10
typedef long long ll ;
bool vis[M] ;
ll f[N][M] , ans[M] ;
int a[N] , D[200*M] ;
int n , m , L , C , Num ;
void SPFA( ll *g ) {
int i = 0 , j = D[0] ;
while ( i < j ) {
i ++ ;
int now = D[i] ;
for (int k = 1 ; k <= Num ; k ++ ) {
int ns = (now + a[k]) % a[1] ;
if ( g[ns] > g[now] + a[k] ) {
g[ns] = g[now] + a[k] ;
if ( !vis[ns] ) {
vis[ns] = 1 ;
D[++j] = ns ;
}
}
}
vis[now] = 0 ;
}
}
int main() {
freopen( "bag.in" , "r" , stdin ) ;
freopen( "bag.out" , "w" , stdout ) ;
scanf( "%d%d" , &n , &m ) ;
for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &a[i] ) ;
scanf( "%d%d" , &L , &C ) ;
for (int i = 1 ; i <= n ; i ++ ) if ( a[i] < L ) Num ++ ;
sort( a + 1 , a + n + 1 ) ;
memset( f , 63 , sizeof(f) ) ;
ll st = f[0][0] ;
f[0][0] = 0 ;
for (int i = 0 ; i <= C ; i ++ ) {
D[0] = 0 ;
for (int j = 0 ; j < a[1] ; j ++ )
if ( f[i][j] != st ) D[++D[0]] = j , vis[j] = 1 ;
SPFA( f[i] ) ;
for (int j = 0 ; j < a[1] ; j ++ ) {
for (int k = Num + 1 ; k <= n ; k ++ ) {
int ns = (a[k] + j) % a[1] ;
f[i+1][ns] = min( f[i+1][ns] , f[i][j] + a[k] ) ;
}
}
}
for (int i = 0 ; i < a[1] ; i ++ ) {
ans[i] = 1e17 ;
for (int j = 0 ; j <= C ; j ++ ) ans[i] = min( ans[i] , f[j][i] ) ;
}
for (int i = 1 ; i <= m ; i ++ ) {
ll W ;
scanf( "%lld" , &W ) ;
if ( ans[W%a[1]] <= W ) printf( "Yes\n" ) ;
else printf( "No\n" ) ;
}
return 0 ;
}
以上.