NOIP 模拟 $29\; \rm 完全背包问题$
题解 \(by\;zj\varphi\)
一道 \(\rm dp\) 题。
现将所有种类从小到大排序,然后判断,若最小的已经大于了 \(\rm l\),那么直接就是一个裸的完全背包,因为选的总数量有限制。
设 \(\rm f_{i,j,k}\) 为选了前 \(\rm i\) 种物品,总数为 \(\rm j\),容量为 \(\rm k\),是否可行,转移很简单。
对于另一种情况,能构造出的最小差距就是 \(v_1\),那么只要记录一下模 \(\rm v_1\) 的值即可。
设 \(\rm f_{i,j}\) 为选了 \(\rm i\) 个有限制的物品,模数为 \(j\) 的状态下最小和为多少,则有转移方程:
\[\rm f_{i,j}=\min(f_{i,j},f_{i,(j-v_i)mod\;v_1}+v_i)\;\; v_i<l\\
f_{i,j}=\min(f_{i,j},f_{i-1,(j-v_i)mod\;v_1}+v_i)\;\; v_i\ge l
\]
发现这个转移会出现环,所以直接最短路。
#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
namespace IO{
char buf[1<<21],*p1=buf,*p2=buf;
#define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
struct nanfeng_stream{
template<typename T>inline nanfeng_stream &operator>>(T &x) {
ri f=0;x=0;register char ch=gc();
while(!isdigit(ch)) {f|=ch=='-';ch=gc();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
return x=f?-x:x,*this;
}
}cin;
}
using IO::cin;
namespace nanfeng{
#define node(nm,v,dis) (node){nm,v,dis}
#define FI FILE *IN
#define FO FILE *OUT
template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
typedef long long ll;
static const int N=51,M=3e5+7,C=31,V=1e4+7;
int v[N],n,m,l,c;
bool vis[C][V];
ll dis[C][V];
struct node{int nm,v;ll dis;};
std::queue<node> que;
std::bitset<M> f[N][C];
inline void spfa() {
memset(dis,127,sizeof(dis));
dis[0][0]=0;
que.push(node(0,0,0));
while(!que.empty()) {
node nw=que.front();que.pop();
vis[nw.nm][nw.v]=0;
for (ri i(2);i<=n;p(i)) {
int tmp;
if (v[i]<l) {
if (dis[nw.nm][tmp=(nw.v+v[i])%v[1]]>nw.dis+v[i]) {
dis[nw.nm][tmp]=nw.dis+v[i];
if (!vis[nw.nm][tmp]) que.push(node(nw.nm,tmp,nw.dis+v[i])),vis[nw.nm][tmp]=1;
}
} else if (nw.nm<c) {
if (dis[nw.nm+1][tmp=(nw.v+v[i])%v[1]]>nw.dis+v[i]) {
dis[nw.nm+1][tmp]=nw.dis+v[i];
if (!vis[nw.nm+1][tmp]) que.push(node(nw.nm+1,tmp,nw.dis+v[i])),vis[nw.nm+1][tmp]=1;
}
}
}
}
}
inline int main() {
//FI=freopen("nanfeng.in","r",stdin);
//FO=freopen("nanfeng.out","w",stdout);
cin >> n >> m;
for (ri i(1);i<=n;p(i)) cin >> v[i];
cin >> l >> c;
std::sort(v+1,v+n+1);
if (v[1]>=l) {
f[0][0][0]=1;
for (ri i(1);i<=n;p(i)) {
for (ri j(0);j<=c;p(j)) {
f[i][j]=f[i-1][j];
if (j) f[i][j]|=f[i][j-1]<<v[i];
}
}
for (ri i(0);i<c;p(i)) f[n][c]|=f[n][i];
for (ri i(1);i<=m;p(i)) {
ll w;cin >> w;
if (w>=M) puts("No");
else printf("%s\n",f[n][c][w]?"Yes":"No");
}
} else if (v[1]<l) {
spfa();
for (ri i(0);i<c;p(i))
for (ri j(0);j<v[1];p(j)) dis[c][j]=cmin(dis[c][j],dis[i][j]);
for (ri i(1);i<=m;p(i)) {
ll w;cin >> w;
printf("%s\n",w>=dis[c][w%v[1]]?"Yes":"No");
}
}
return 0;
}
}
int main() {return nanfeng::main();}\