NOIP 模擬 $29\; \rm 完全揹包問題$
阿新 • • 發佈:2021-08-06
題解
\[\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
\]
題解 \(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\) 的狀態下最小和為多少,則有轉移方程:
發現這個轉移會出現環,所以直接最短路。
#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();}\