题目大意:
有n种物品,物品的体积分别为V1, V2, · · · , Vn,且每种物品的数量都可以看做是无 限多的。 现在有m次询问,每次询问给定一个容量为Wi的背包,请你回答是否存在一种物品选择方案,使得背包恰好能被完全装满(仅考虑体积,忽略长、 宽、 高等其他因 素)。 同时,要求所有选出的物品中,体积不小于L的物品总数量不能超过C件。
思路:
好像体积大于L的部分可以直接暴力DP而不会超时。然后我们再来考虑体积小于L的部分。
这就好比一个完全背包,然后问你体积W是否可以刚好被填满,但是W太大了,显然不可以直接DP。
我们考虑一个性质,如果
并且
那么如果v体积可以被表示出来,w也一定可以被表示出来。于是我们可以把体积按照
的剩余类来划分,同时DP出可以满足每个剩余类的最小的体积,这样就可以直接和询问比较大小了。
考虑怎么DP,因为每一个物品的数量不限,所以DP过程中状态转移图势必会出现环,发现我们其实要求的就是这个状态转移图的单源最短路,设置一个源点,根据之前的体积大于L的部分向剩余类里面的点连边,然后每一个点可以选择任何一个物品,即从
连向
,边权为
,然后SPFA即可。
/*===========================
* Author : ylsoi
* Problem : jzoj4916
* Algorithm : DP
* Time : 2018.6.14
* ========================*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
#include<bitset>
#include<queue>
using namespace std;
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf (0x3f3f3f3f)
const int maxn=50+10;
const int maxv=1e4+10;
int n,m,vo[maxn],L,C;
int dp[maxv][40],beg[maxv],cnte,dis[maxv];
struct edge{int to,last,w;}E[maxn*maxv];
void add(int u,int v,int w){
++cnte;
E[cnte].to=v;
E[cnte].last=beg[u];
beg[u]=cnte;
E[cnte].w=w;
}
void init(){
scanf("%d%d",&n,&m);
REP(i,1,n)scanf("%d",&vo[i]);
sort(vo+1,vo+n+1);
scanf("%d%d",&L,&C);
REP(i,0,vo[1]-1)REP(j,0,C)
dp[i][j]=inf;
dp[0][0]=0;
REP(i,1,n){
if(vo[i]<L)continue;
REP(k,1,C)REP(j,0,vo[1]-1){
int u=((j-vo[i])%vo[1]+vo[1])%vo[1];
chkmin(dp[j][k],dp[u][k-1]+vo[i]);
}
}
}
void SPFA(){
REP(i,0,vo[1]-1){
REP(j,1,n){
if(vo[j]>=L)break;
int v=(i+vo[j])%vo[1];
add(i,v,vo[j]);
}
}
REP(i,0,vo[1]-1){
dis[i]=inf;
REP(k,0,C)chkmin(dis[i],dp[i][k]);
}
queue<int>qu;
bool vis[maxv]={0};
REP(i,0,vo[1]-1)if(dis[i]!=inf)
qu.push((int)i),vis[i]=1;
while(qu.size()){
int u=qu.front();
qu.pop();
vis[u]=0;
MREP(i,u){
int v=E[i].to;
if(chkmin(dis[v],dis[u]+E[i].w) && !vis[v]){
vis[v]=1;
qu.push(v);
}
}
}
}
int main(){
init();
SPFA();
REP(i,1,m){
ll u;
scanf("%lld",&u);
if(dis[u%vo[1]]==inf){
puts("No");
continue;
}
if(dis[u%vo[1]]<=u)puts("Yes");
else puts("No");
}
return 0;
}